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 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 :
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.
execvedalam shebang walaupun tidak masuk akal untuk memiliki path relatif di shebang.
/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
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.
strace(dikonversi ke /usr/bin/stracebeberapa titik) dengan 2 argumen.