Apakah mungkin untuk memiliki shebang yang, alih-alih menentukan path ke interpreter, ia memiliki nama interpreter, dan membiarkan shell menemukannya melalui $ PATH?
Jika tidak, adakah alasannya?
Apakah mungkin untuk memiliki shebang yang, alih-alih menentukan path ke interpreter, ia memiliki nama interpreter, dan membiarkan shell menemukannya melalui $ PATH?
Jika tidak, adakah alasannya?
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 seperti execvp
untuk melakukan pencarian PATH) atau dalam shebang (yang lebih kurang merutekan kembali execve
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.
execve
dalam shebang walaupun tidak masuk akal untuk memiliki path relatif di shebang.
/lib64/ld-linux-x86-64.so.2
(lihat ldd
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 Invoke wine
ketika Anda menjalankan mereka, kelas dan jar file Java memanggil java
, dll dll
Ada lebih banyak hal yang terjadi daripada yang terlihat. #!
baris ditafsirkan oleh kernel Unix atau Linux, #!
bukan merupakan aspek shell. Ini berarti PATH
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 mewarisi PATH
variabel lingkungan. env
menemukan (dalam contoh ini) perl
di PATH
dan menggunakan execve(2)
system call untuk mendapatkan kernel untuk menjalankan perl
executable.
$ 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.
strace
(dikonversi ke /usr/bin/strace
beberapa titik) dengan 2 argumen.