Ini mungkin pertanyaan konyol, tapi saya tetap bertanya. Jika saya telah menyatakan shebang
#!/bin/bash
di awal my_shell_script.sh
, jadi saya selalu harus memanggil skrip ini menggunakan bash
[my@comp]$bash my_shell_script.sh
atau bisakah saya menggunakan mis
[my@comp]$sh my_shell_script.sh
dan skrip saya menentukan shell yang berjalan menggunakan shebang? Apakah sama halnya dengan ksh
shell? Saya menggunakan AIX.
scripting
executable
shebang
jrara
sumber
sumber
chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory
Jawaban:
The shebang
#!
adalah turunan dibaca manusia dari angka ajaib yang terdiri dari string byte0x23 0x21
, yang digunakan olehexec()
keluarga fungsi untuk menentukan apakah file yang akan dieksekusi adalah script atau biner. Ketika shebang hadir,exec()
akan menjalankan executable yang ditentukan setelah shebang sebagai gantinya.Perhatikan bahwa ini berarti bahwa jika Anda menjalankan skrip dengan menentukan penerjemah pada baris perintah, seperti yang dilakukan dalam kedua kasus yang diberikan dalam pertanyaan,
exec()
akan mengeksekusi penerjemah yang ditentukan pada baris perintah, itu bahkan tidak akan melihat skrip.Jadi, seperti yang telah dicatat orang lain, jika Anda ingin
exec()
memanggil juru bahasa yang ditentukan pada baris shebang, skrip harus memiliki bit yang dapat dieksekusi dan dipanggil sebagai./my_shell_script.sh
.Perilaku ini mudah ditunjukkan dengan skrip berikut:
Penjelasan:
#!/bin/ksh
mendefinisikanksh
menjadi penerjemah.$$
memegang PID dari proses saat ini./proc/pid/exe
adalah symlink ke executable dari proses (setidaknya di Linux; di AIX, /proc/$$/object/a.out adalah tautan ke executable).readlink
akan menampilkan nilai tautan simbolik.Contoh:
Catatan : Saya mendemonstrasikan ini di Ubuntu, di mana shell default
/bin/sh
adalah symlink ke dash yaitu/bin/dash
dan/bin/ksh
symlink ke/etc/alternatives/ksh
, yang pada gilirannya adalah symlink ke/bin/pdksh
.sumber
exec()
dimaksud dalam jawaban ini adalah panggilan sistem, perintahnyaexec
adalah shell builtin, itulah sebabnya Anda tidak dapat menjalankanexec
program dari Node.js atau Java. Namun, perintah shell apa pun yang dijalankan oleh mis.Runtime.exec()
Di Java akhirnya diproses olehexec()
panggilan sistem.child_process.{exec(),execFile(),spawn()
} semua akan diimplementasikan menggunakan Cexec()
(throughprocess
).Ya itu. Ngomong-ngomong itu bukan pertanyaan konyol. Referensi untuk jawaban saya ada di sini . Memulai Script Dengan #!
Ini disebut garis shebang atau "bang".
Itu tidak lain adalah jalur absolut menuju juru bahasa Bash.
Ini terdiri dari tanda angka dan karakter tanda seru (#!), Diikuti oleh path lengkap ke penerjemah seperti / bin / bash.
Semua skrip di Linux dijalankan menggunakan interpreter yang ditentukan pada baris pertama. Hampir semua skrip bash sering dimulai dengan #! / Bin / bash (dengan asumsi bahwa Bash telah diinstal di / bin) Ini memastikan bahwa Bash akan digunakan untuk menafsirkan skrip, bahkan jika dijalankan di bawah shell lain. Shebang diperkenalkan oleh Dennis Ritchie antara Versi 7 Unix dan 8 di Bell Laboratories. Itu kemudian juga ditambahkan ke jalur BSD di Berkeley.
Mengabaikan Garis Juru Bahasa (shebang)
Jika Anda tidak menentukan jalur juru bahasa, standarnya biasanya adalah / bin / sh. Namun, Anda disarankan untuk menyetel #! / Bin / bash line.
sumber
#!/usr/bin/perl
#!/usr/local/bin/python
#!/usr/local/bin/ruby
entri shebang umum lainnya yang digunakan untuk mendukung banyak sistem adalah dengan menggunakan env untuk menemukan juru bahasa yang ingin Anda gunakan, seperti#!/usr/bin/env perl
#!/usr/bin/env python
env
, yang mana yang sebenarnya lebih disukai? Python dan Perl sering digunakanenv
, sedangkan pada shellscripts, ini sering dihilangkan dan shebang menunjuk ke shell yang dimaksud.env
untuk menemukan program dalam $ PATH sedikit meretas. Itu tidak mengatur variabel lingkungan seperti namanya. $ PATH mungkin hasil yang berbeda untuk pengguna yang berbeda. Tapi ini membantu skrip berjalan tanpa modifikasi pada sistem yang menempatkan penerjemah perl yang wajar di beberapa tempat yang aneh.The
exec
system call dari kernel Linux mengerti shebangs (#!
) nativeKetika Anda melakukannya di bash:
di Linux, ini memanggil
exec
system call dengan path./something
.Baris kernel ini dipanggil pada file yang diteruskan ke
exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25Itu membaca byte pertama file, dan membandingkannya
#!
.Jika perbandingannya benar, maka seluruh baris diuraikan oleh kernel Linux, yang membuat
exec
panggilan lain dengan path/usr/bin/env python
dan file saat ini sebagai argumen pertama:dan ini berfungsi untuk bahasa skrip apa pun yang digunakan
#
sebagai karakter komentar.Dan ya, Anda dapat membuat loop tanpa batas dengan:
Bash mengenali kesalahan:
#!
Kebetulan bisa dibaca manusia, tapi itu tidak wajib.Jika file dimulai dengan byte yang berbeda, maka
exec
panggilan sistem akan menggunakan penangan yang berbeda. Handler internal terpenting lainnya adalah file yang dapat dieksekusi ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 yang memeriksa byte7f 45 4c 46
(yang juga merupakan manusia dapat dibaca untuk.ELF
). Mari kita konfirmasi dengan membaca 4 byte pertama/bin/ls
, yang merupakan executable ELF:keluaran:
Jadi ketika kernel melihat byte-byte itu, ia mengambil file ELF, memasukkannya ke dalam memori dengan benar, dan memulai proses baru dengannya. Lihat juga: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Akhirnya, Anda dapat menambahkan penangan shebang Anda sendiri dengan
binfmt_misc
mekanismenya. Misalnya, Anda dapat menambahkan penangan khusus untuk.jar
file . Mekanisme ini bahkan mendukung penangan melalui ekstensi file. Aplikasi lain adalah untuk menjalankan executable dari arsitektur yang berbeda dengan QEMU .Saya tidak berpikir POSIX menentukan shebangs, namun: https://unix.stackexchange.com/a/346214/32558 , meskipun ia menyebutkannya di bagian rasional, dan dalam bentuk "jika skrip yang dapat dieksekusi didukung oleh sistem sesuatu mungkin terjadi ".
sumber
./something
dari shell tidak akan melewatkan path lengkap keexec
, tetapi persis path yang dimasukkan. Bisakah Anda memperbaiki ini dalam jawaban Anda? Lakukanecho "$0"
dalam skrip Anda dan Anda akan melihat ini masalahnya.Bahkan, jika Anda mengambilnya secara konsekuen, executable yang dicatat di baris shebang, hanyalah executable. Masuk akal untuk menggunakan beberapa penerjemah teks sebagai yang dapat dieksekusi, tetapi itu tidak perlu. Hanya untuk klarifikasi dan demonstrasi, saya membuat tes yang agak tidak berguna:
Bernama file test.txt dan mengatur bit exectuable
chmod u+x test.txt
, kemudian "disebut" itu:./test.txt
. Seperti yang diharapkan, isi file adalah output. Dalam hal ini, kucing tidak mengabaikan garis shebang. Ini hanya menampilkan semua lini. Setiap penerjemah yang berguna karenanya harus dapat mengabaikan garis shebang ini. Untuk bash, perl dan PHP, ini hanyalah sebuah baris komentar. Jadi ya, ini mengabaikan garis shebang.sumber
Dari apa yang saya kumpulkan, setiap kali file memiliki bit yang dapat dieksekusi dan dipanggil, kernel menganalisis header file untuk menentukan bagaimana melanjutkan (sejauh yang saya tahu, Anda dapat menambahkan penangan khusus untuk format file khusus melalui LKMs). Jika file tersebut muncul sebagai file teks dengan #! kombinasi pada awalnya, pelaksanaannya dikirim ke executable lain (biasanya shell of macam), jalan yang akan ditentukan secara langsung setelah shebang tersebut, di baris yang sama. Kernel kemudian melanjutkan untuk mengeksekusi shell dan meneruskan file untuk ditangani.
Singkatnya, tidak masalah shell mana yang Anda gunakan skrip - kernel akan mengirimkan eksekusi ke salah satu cara yang sesuai.
sumber
bash ./myscript.sh
dan./myscript.sh
.