Misalkan shell default untuk akun saya adalah zsh tetapi saya membuka terminal dan menjalankan bash dan mengeksekusi skrip bernama prac002.sh
, interpreter shell mana yang akan digunakan untuk mengeksekusi skrip, zsh atau bash? Perhatikan contoh berikut:
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf:
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)
papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh
Enter username : Rex
Rex
# Which interpreter did it just use?
** EDIT: ** Inilah isi naskahnya
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh
read -p "Enter username : " uname
echo $uname
. prac002.sh
, dengan asumsi skrip Anda ada di dir saat ini.. ./prac002.sh
dan itu akan berjalan dengan shell saat ini, yaitu, dot (.
), space () diikuti oleh path skrip Anda. Ini disebut dot-sourcing skrip Anda. ;-)Jawaban:
Karena skrip tidak dimulai dengan
#!
garis shebang yang menunjukkan penerjemah mana yang akan digunakan, POSIX mengatakan bahwa :Ungkapan itu sedikit ambigu, dan cangkang yang berbeda memiliki interpretasi yang berbeda.
Dalam hal ini, Bash akan menjalankan skrip menggunakan dirinya sendiri . Di sisi lain, jika Anda menjalankannya dari zsh, zsh akan menggunakan
sh
(apa pun yang ada di sistem Anda) sebagai gantinya.Anda dapat memverifikasi perilaku itu untuk kasus ini dengan menambahkan baris ini ke skrip:
Anda akan mencatat bahwa, dari Bash, baris pertama menampilkan versi Anda, sedangkan yang kedua tidak pernah mengatakan apa-apa, tidak peduli shell mana yang Anda gunakan.
/bin/sh
, katakanlah,dash
maka baris tidak akan menghasilkan apa pun ketika skrip dieksekusi dari zsh atau dash./bin/sh
adalah tautan ke Bash, Anda akan melihat output baris pertama dalam semua kasus./bin/sh
adalah versi yang berbeda dari Bash dari yang Anda gunakan secara langsung, Anda akan melihat output yang berbeda ketika Anda menjalankan script dari bash langsung dan dari zsh.The
ps -p $$
perintah dari jawaban rools ini juga akan menampilkan informasi yang berguna tentang perintah shell yang digunakan untuk menjalankan script.sumber
execl()
panggilan terjadi ketika skrip shell tidak berisi shebang dan dieksekusi sebagaiscriptname
? Apakah itu tidak terjadi ketika skrip shell dieksekusibash scriptname
? Apakah itu tidak terjadi ketika skrip shell berisi shebang dan dieksekusi sebagaiscriptname
?Karena file tersebut bukan tipe yang dapat dieksekusi yang dikenali oleh sistem, dan dengan asumsi Anda memiliki izin untuk mengeksekusi file itu,
execve()
panggilan sistem biasanya akan gagal dengan kesalahanENOEXEC
( bukan yang dapat dieksekusi ).Apa yang terjadi kemudian tergantung pada fungsi aplikasi dan / atau perpustakaan yang digunakan untuk menjalankan perintah.
Itu bisa berupa shell, fungsi
execlp()
/execvp()
libc.Sebagian besar aplikasi lain akan menggunakan salah satu dari mereka ketika mereka menjalankan perintah. Mereka akan memanggil shell misalnya dengan menggunakan
system("command line")
fungsi libc yang biasanya akan memanggilsh
untuk mem-parsing baris perintah itu (jalur yang dapat ditentukan pada waktu kompilasi (seperti/bin/sh
vs/usr/xpg4/bin/sh
pada Solaris)), atau memanggil shell yang disimpan dalam$SHELL
dirinya sendiri sepertivi
dengan!
perintahnya, atauxterm -e 'command line'
dan banyak perintah lainnya (su user -c
akan meminta shell login pengguna alih-alih$SHELL
).Secara umum, file teks tanpa-shebang yang tidak dimulai
#
dianggap sebagaish
skrip. Yangsh
itu akan bervariasi.execlp()
/execvp()
, setelahexecve()
kembaliENOEXEC
biasanya akan memintanyash
. Untuk sistem yang memiliki lebih dari satush
karena mereka dapat memenuhi lebih dari satu standar, yangsh
biasanya akan ditentukan pada waktu kompilasi (dari aplikasi menggunakanexecvp()
/execlp()
dengan menghubungkan gumpalan kode yang berbeda yang merujuk ke jalur yang berbeda dengansh
). Sebagai contoh, pada Solaris, itu akan menjadi/usr/xpg4/bin/sh
(standar, POSIXsh
) atau/bin/sh
(cangkang Bourne (cangkang kuno) pada Solaris 10 dan lebih lama, ksh93 dalam Solaris 11).Ketika datang ke kerang, ada banyak variasi.
bash
, AT&Tksh
, shell Bourne biasanya akan menafsirkan skrip itu sendiri (dalam proses anak kecualiexec
digunakan) setelah mensimulasikan aexecve()
, yang tidak mengatur semua variabel yang tidak diekspor, menutup semua fds close-on-exec, menghapus semua jebakan kustom, alias, fungsi ... (bash
akan menafsirkan skrip dalamsh
mode).yash
akan mengeksekusi sendiri (dengan modesh
sepertiargv[0]
dalamsh
) untuk menafsirkannya.zsh
,pdksh
,ash
Kerang berbasis biasanya akan memanggilsh
(jalur yang ditentukan pada saat kompilasi).Untuk
csh
dantcsh
(dansh
beberapa BSD awal), jika karakter pertama file tersebut#
, maka mereka akan mengeksekusi sendiri untuk menafsirkannya, dansh
sebaliknya. Yang kembali ke waktu pre-peristiwa di manacsh
tidak mengakui#
sebagai komentar tapi tidak Bourne shell, sehingga#
merupakan petunjuk bahwa ia adalah script csh.fish
(setidaknya versi 2.4.0), baru saja mengembalikan kesalahan jikaexecve()
gagal (tidak mencoba memperlakukannya sebagai skrip).Beberapa shell (suka
bash
atau AT&Tksh
) pertama-tama akan mencoba untuk menentukan apakah file tersebut dimaksudkan sebagai skrip atau tidak. Jadi Anda mungkin menemukan bahwa beberapa shell akan menolak untuk mengeksekusi skrip jika ada karakter NUL di beberapa byte pertama.Juga perhatikan bahwa jika
execve()
gagal dengan ENOEXEC tetapi file tersebut memang memiliki garis shebang, beberapa shell mencoba menafsirkan garis shebang itu sendiri.Jadi beberapa contoh:
$SHELL
adalah/bin/bash
,xterm -e 'myscript with args'
akanmyscript
ditafsirkan olehbash
dish
modus. Sementara denganxterm -e myscript with args
,xterm
akan digunakanexecvp()
sehingga skrip akan ditafsirkan olehsh
.su -c myscript
pada Solaris 10 di manaroot
shell login adalah/bin/sh
dan/bin/sh
shell Bourne akanmyscript
ditafsirkan oleh shell Bourne./usr/xpg4/bin/awk 'BEGIN{system("myscript")'
pada Solaris 10 akan ditafsirkan oleh/usr/xpg4/bin/sh
(sama untuk/usr/xpg4/bin/env myscript
).find . -prune -exec myscript {} \;
pada Solaris 10 (menggunakanexecvp()
) akan menafsirkannya/bin/sh
bahkan dengan/usr/xpg4/bin/find
, bahkan dalam lingkungan POSIX (bug kepatuhan).csh -c myscript
akan menafsirkannyacsh
jika dimulai dengan#
, dengansh
sebaliknya.Secara keseluruhan, Anda tidak dapat memastikan shell apa yang akan digunakan untuk menafsirkan skrip itu jika Anda tidak tahu bagaimana dan oleh apa itu akan dipanggil.
Dalam kasus apa pun,
read -p
ini adalahbash
hanya sintaks, jadi Anda harus memastikan bahwa skrip diinterpretasikan olehbash
(dan menghindari.sh
ekstensi yang menyesatkan ). Entah Anda tahu jalur yangbash
dapat dieksekusi dan gunakan:Atau Anda dapat mencoba dan mengandalkan
$PATH
pencarian yangbash
dapat dieksekusi (dengan asumsibash
diinstal) dengan menggunakan:(
env
Hampir di mana-mana ditemukan di/usr/bin
). Atau, Anda dapat membuatnya POSIX + Bourne kompatibel dalam hal ini Anda dapat menggunakan/bin/sh
. Semua sistem akan memiliki/bin/sh
. Pada sebagian besar dari mereka itu akan (sebagian besar) kompatibel dengan POSIX, tetapi Anda mungkin masih menemukan shell Bourne di sana.sumber
Ketika Anda tidak memiliki garis
#!
(disebut shebang ), sh digunakan. Untuk memeriksanya, Anda dapat menjalankan skrip berikut.Di komputer saya saya dapatkan
bahkan jika shell default saya adalah zsh . Ini menggunakan bash karena pada mesin saya, perintah sh diimplementasikan oleh bash .
sumber