Apakah mungkin untuk memiliki shebang yang, alih-alih menentukan path ke interpreter, ia memiliki nama interpreter, dan membiarkan shell menemukannya melalui $ PATH?
Pencarian PATH adalah fitur dari pustaka C standar di userspace, seperti variabel lingkungan pada umumnya. Kernel tidak melihat variabel lingkungan kecuali ketika melewati lingkungan dari pemanggil execveke proses baru.
Kernel tidak melakukan interpretasi apa pun pada path in execve(terserah fungsi wrapper seperti execvpuntuk melakukan pencarian PATH) atau dalam shebang (yang lebih kurang merutekan kembali execvepanggilan secara internal). Jadi Anda harus meletakkan jalur absolut di shebang¹. The pelaksanaan shebang asli hanya beberapa baris kode, dan belum secara signifikan diperluas sejak.
Dalam versi pertama Unix, shell melakukan pekerjaan memohon sendiri ketika Anda melihat Anda memohon sebuah skrip. Shebang ditambahkan dalam kernel karena beberapa alasan (meringkas alasan oleh Dennis Ritchie :
Penelepon tidak perlu khawatir apakah program yang akan dijalankan adalah skrip shell atau biner asli.
Script itu sendiri menentukan penerjemah apa yang akan digunakan, bukan penelepon.
Kernel menggunakan nama skrip dalam log.
Pathless shebang akan membutuhkan untuk menambah kernel untuk mengakses variabel dan proses lingkungan PATH, atau untuk meminta kernel mengeksekusi program userspace yang melakukan pencarian PATH. Metode pertama membutuhkan penambahan kompleksitas yang tidak proporsional ke kernel. Metode kedua sudah mungkin dengan #!/usr/bin/envshebang .
¹ Jika Anda meletakkan jalur relatif, itu ditafsirkan secara relatif ke direktori saat ini dari proses (bukan direktori yang berisi skrip), yang hampir tidak berguna di shebang.
Tidak, kernel tidak memerlukan path absolut di execvedalam shebang walaupun tidak masuk akal untuk memiliki path relatif di shebang.
Stéphane Chazelas
3
Bagi siapa pun yang penasaran tentang bagaimana "shebang merutekan panggilan eksekutif ke dalam": Ini sebenarnya bagian dari mekanisme umum untuk menjalankan penerjemah pada executable yang membutuhkannya. Executable ELF yang terhubung secara dinamis "ditafsirkan" oleh /lib64/ld-linux-x86-64.so.2(lihat lddoutput). Linux menjadikannya sepenuhnya generik: binfmtdukungan (sejak 2.1.43) memungkinkan Anda mendaftar pasangan interpreter-path / magic-number-atau-file-extension. Anda dapat memiliki PE32 .exes Invoke wineketika Anda menjalankan mereka, kelas dan jar file Java memanggil java, dll dll
Peter Cordes
#! / usr / bin / env -S [shebang] diperlukan untuk saya menjalankan simpul tanpa mengetahui jalurnya (menggunakan nvm - yang menempatkannya di lokasi yang berbeda dari yang saya perkirakan).
Ada lebih banyak hal yang terjadi daripada yang terlihat. #!baris ditafsirkan oleh kernel Unix atau Linux, #!bukan merupakan aspek shell. Ini berarti PATHtidak ada pada saat kernel memutuskan apa yang akan dieksekusi.
Cara paling umum untuk berurusan dengan tidak mengetahui yang dapat dijalankan untuk dijalankan, atau untuk memanggil perldengan cara portabel atau serupa, adalah menggunakan #!/usr/bin/env perl. Kernel dieksekusi /usr/bin/env, yang mewarisi PATHvariabel lingkungan. envmenemukan (dalam contoh ini) perldi PATHdan menggunakan execve(2)system call untuk mendapatkan kernel untuk menjalankan perlexecutable.
$ strace sleep 1
execve("/usr/bin/sleep",["sleep","1"],[/*99 vars */])=0
Konversi ke path lengkap dilakukan oleh shell (lebih umum: di userspace). Kernel mengharapkan nama file / jalur yang dapat diakses langsung.
Jika Anda ingin sistem menemukan executable Anda dengan melihat melalui variabel PATH, Anda dapat menulis ulang shebang Anda sebagai #!/usr/bin/env EXEC.
Tetapi juga dalam hal ini bukan kernel yang melakukan pencarian.
Konversi ke path lengkap dilakukan oleh shell Terima kasih, meskipun ... adalah contoh yang seharusnya menggambarkan itu? Seperti yang saya lihat, shell hanya berjalan strace(dikonversi ke /usr/bin/stracebeberapa titik) dengan 2 argumen.
Jawaban:
Pencarian PATH adalah fitur dari pustaka C standar di userspace, seperti variabel lingkungan pada umumnya. Kernel tidak melihat variabel lingkungan kecuali ketika melewati lingkungan dari pemanggil
execve
ke proses baru.Kernel tidak melakukan interpretasi apa pun pada path in
execve
(terserah fungsi wrapper sepertiexecvp
untuk melakukan pencarian PATH) atau dalam shebang (yang lebih kurang merutekan kembaliexecve
panggilan secara internal). Jadi Anda harus meletakkan jalur absolut di shebang¹. The pelaksanaan shebang asli hanya beberapa baris kode, dan belum secara signifikan diperluas sejak.Dalam versi pertama Unix, shell melakukan pekerjaan memohon sendiri ketika Anda melihat Anda memohon sebuah skrip. Shebang ditambahkan dalam kernel karena beberapa alasan (meringkas alasan oleh Dennis Ritchie :
Pathless shebang akan membutuhkan untuk menambah kernel untuk mengakses variabel dan proses lingkungan
PATH
, atau untuk meminta kernel mengeksekusi program userspace yang melakukan pencarian PATH. Metode pertama membutuhkan penambahan kompleksitas yang tidak proporsional ke kernel. Metode kedua sudah mungkin dengan#!/usr/bin/env
shebang .¹ Jika Anda meletakkan jalur relatif, itu ditafsirkan secara relatif ke direktori saat ini dari proses (bukan direktori yang berisi skrip), yang hampir tidak berguna di shebang.
sumber
execve
dalam shebang walaupun tidak masuk akal untuk memiliki path relatif di shebang./lib64/ld-linux-x86-64.so.2
(lihatldd
output). Linux menjadikannya sepenuhnya generik:binfmt
dukungan (sejak 2.1.43) memungkinkan Anda mendaftar pasangan interpreter-path / magic-number-atau-file-extension. Anda dapat memiliki PE32.exe
s Invokewine
ketika Anda menjalankan mereka, kelas dan jar file Java memanggiljava
, dll dllAda lebih banyak hal yang terjadi daripada yang terlihat.
#!
baris ditafsirkan oleh kernel Unix atau Linux,#!
bukan merupakan aspek shell. Ini berartiPATH
tidak ada pada saat kernel memutuskan apa yang akan dieksekusi.Cara paling umum untuk berurusan dengan tidak mengetahui yang dapat dijalankan untuk dijalankan, atau untuk memanggil
perl
dengan cara portabel atau serupa, adalah menggunakan#!/usr/bin/env perl
. Kernel dieksekusi/usr/bin/env
, yang mewarisiPATH
variabel lingkungan.env
menemukan (dalam contoh ini)perl
diPATH
dan menggunakanexecve(2)
system call untuk mendapatkan kernel untuk menjalankanperl
executable.sumber
Konversi ke path lengkap dilakukan oleh shell (lebih umum: di userspace). Kernel mengharapkan nama file / jalur yang dapat diakses langsung.
Jika Anda ingin sistem menemukan executable Anda dengan melihat melalui variabel PATH, Anda dapat menulis ulang shebang Anda sebagai
#!/usr/bin/env EXEC
.Tetapi juga dalam hal ini bukan kernel yang melakukan pencarian.
sumber
strace
(dikonversi ke/usr/bin/strace
beberapa titik) dengan 2 argumen.