#! / bin / sh -
Apakah (atau paling tidak itu) sering merupakan shebang yang direkomendasikan untuk ditafsirkan oleh sebuah skrip /bin/sh
.
Kenapa tidak adil #! /bin/sh
atau #!/bin/sh
?
Untuk apa itu -
?
#! / bin / sh -
Apakah (atau paling tidak itu) sering merupakan shebang yang direkomendasikan untuk ditafsirkan oleh sebuah skrip /bin/sh
.
Kenapa tidak adil #! /bin/sh
atau #!/bin/sh
?
Untuk apa itu -
?
Jawaban:
Itu untuk alasan yang sama seperti mengapa Anda perlu menulis:
rm -- *.txt
Dan tidak
rm *.txt
Kecuali Anda dapat menjamin tidak ada .txt
file di direktori saat ini yang memiliki nama yang dimulai -
.
Di:
rm <arg>
<arg>
dianggap pilihan jika dimulai dengan -
atau file untuk menghapus sebaliknya. Di
rm - <arg>
arg
selalu dianggap sebagai file yang akan dihapus terlepas dari apakah itu dimulai dengan -
atau tidak.
Itu sama untuk sh
.
Ketika seseorang menjalankan skrip yang dimulai dengan
#! /bin/sh
Biasanya dengan:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Sistem mengubahnya menjadi:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
The path/to/the-script
biasanya tidak sesuatu yang di bawah kendali penulis naskah. Penulis tidak dapat memperkirakan di mana salinan skrip akan disimpan atau dengan nama apa. Secara khusus, mereka tidak dapat menjamin bahwa path/to/the-script
dengan yang dipanggil tidak akan dimulai -
(atau +
yang juga merupakan masalah dengan sh
). Itu sebabnya kita perlu di -
sini untuk menandai akhir opsi.
Misalnya, pada sistem saya zcat
(seperti kebanyakan skrip lainnya sebenarnya) adalah salah satu contoh skrip yang tidak mengikuti rekomendasi itu:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Sekarang Anda mungkin bertanya mengapa #! /bin/sh -
dan tidak #! /bin/sh --
?
Meskipun #! /bin/sh --
akan bekerja dengan cangkang POSIX, yang #! /bin/sh -
lebih portabel; khususnya untuk versi kuno sh
. sh
memperlakukan -
sebagai dan akhir opsi mendahului getopt()
dan penggunaan umum --
untuk menandai akhir opsi pada waktu yang lama. Cara shell Bourne (dari akhir 70-an) mengurai argumennya, hanya argumen pertama yang dipertimbangkan untuk opsi jika dimulai dengan -
. Semua karakter setelahnya -
akan diperlakukan sebagai nama opsi; jika tidak ada karakter setelah-
, tidak ada opsi. Kerang yang macet dan semua seperti Bourne kemudian mengenali -
sebagai cara untuk menandai akhir opsi.
Dalam cangkang Bourne (tetapi tidak dalam cangkang mirip Bourne modern), #! /bin/sh -euf
juga akan mengatasi masalah karena hanya argumen pertama yang dipertimbangkan untuk opsi.
Sekarang, orang bisa mengatakan bahwa kita menjadi jagoan di sini, dan itu juga mengapa saya menulis kebutuhan dalam huruf miring di atas:
-
atau +
atau menempatkan mereka dalam sebuah direktori yang namanya dimulai dengan-
atau +
.execvp()
/ execlp()
-type fungsi. Dan dalam hal itu, secara umum Anda memanggil mereka baik the-script
agar itu dicari dalam $PATH
kasus mana argumen path ke execve()
system call biasanya akan dimulai dengan /
(tidak -
atau tidak +
) atau seolah- ./the-script
olah Anda ingin the-script
direktori saat ini dijalankan (dan kemudian jalan dimulai dengan ./
, bukan -
juga bukan +
).Sekarang selain masalah kebenaran teoretis , ada alasan lain mengapa #! /bin/sh -
menjadi direkomendasikan sebagai praktik yang baik . Dan itu kembali ke masa di mana beberapa sistem masih mendukung skrip setuid.
Jika Anda memiliki skrip yang berisi:
#! /bin/sh
/bin/echo "I'm running as root"
Dan skrip itu adalah setuid root (seperti dengan -r-sr-xr-x root bin
izin), pada sistem itu, ketika dijalankan oleh pengguna biasa, the
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
akan dilakukan root
!
Jika pengguna membuat symlink /tmp/-i -> path/to/the-script
dan menjalankannya sebagai -i
, maka itu akan memulai shell interaktif ( /bin/sh -i
) sebagai root
.
The -
akan bekerja di sekitar itu (itu tidak akan bekerja di sekitar masalah ras-kondisi , atau fakta bahwa beberapa sh
implementasi seperti beberapa ksh88
yang berbasis akan lookup argumen naskah tanpa/
di $PATH
meskipun).
Saat ini, hampir tidak ada sistem yang mendukung skrip setuid lebih lama, dan beberapa dari mereka yang masih melakukan (biasanya tidak secara default), akhirnya melakukan a execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])
(di mana <n>
file deskriptor terbuka untuk membaca skrip) yang bekerja di sekitar masalah ini dan kondisi balapan.
Perhatikan bahwa Anda mendapatkan masalah serupa dengan sebagian besar penerjemah, tidak hanya cangkang mirip Bourne. Cangkang non-Bourne umumnya tidak mendukung -
sebagai penanda opsi akhir, tetapi umumnya mendukung --
sebagai gantinya (setidaknya untuk versi modern).
Juga
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Tidak memiliki masalah sebagai argumen berikutnya dianggap sebagai argumen ke -f
pilihan dalam hal apapun, tetapi masih tidak bekerja jika path/to/script
adalah -
(dalam hal ini, dengan sebagian besar sed
/ awk
implementasi, sed
/awk
tidak membaca kode dari -
file, tetapi dari stdin sebagai gantinya).
Perhatikan juga bahwa pada kebanyakan sistem, seseorang tidak dapat menggunakan:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Seperti pada kebanyakan sistem, mekanisme shebang hanya memungkinkan satu argumen setelah jalur juru bahasa.
Seperti apakah akan menggunakan #! /bin/sh -
vs #!/bin/sh -
, itu hanya masalah selera. Saya lebih suka yang pertama karena membuat jalur juru bahasa lebih terlihat dan membuat pemilihan mouse lebih mudah. Ada legenda yang mengatakan bahwa ruang itu dibutuhkan dalam beberapa versi Unix kuno tetapi AFAIK, yang belum pernah diverifikasi.
Referensi yang sangat bagus tentang Unix shebang dapat ditemukan di https://www.in-ulm.de/~mascheck/various/shebang
bash
menerima opsi seperti setiap shell lainnya. Menjadi shell Bourne-like dan POSIX, bash
menerima keduanya #! /bin/bash -
dan #! /bin/bash --
.