Dalam kasus yang paling umum, $0
akan berisi path, absolut atau relatif terhadap skrip, jadi
script_path=$(readlink -e -- "$0")
(dengan asumsi ada readlink
perintah dan itu mendukung -e
) umumnya adalah cara yang cukup baik untuk mendapatkan path absolut kanonik ke skrip.
$0
ditugaskan dari argumen yang menentukan skrip yang diteruskan ke penerjemah.
Misalnya, di:
the-shell -shell-options the/script its args
$0
dapatkan the/script
.
Ketika Anda menjalankan:
the/script its args
Shell Anda akan melakukan:
exec("the/script", ["the/script", "its", "args"])
Jika skrip berisi #! /bin/sh -
she-bang misalnya, sistem akan mengubahnya menjadi:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "the/script", "its", "args"])
(jika tidak mengandung she-bang, atau lebih umum lagi jika sistem mengembalikan kesalahan ENOEXEC, maka shell Anda yang akan melakukan hal yang sama)
Ada pengecualian untuk skrip setuid / setgid pada beberapa sistem, di mana sistem akan membuka skrip pada beberapa fd
x
dan menjalankannya sebagai gantinya:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "/dev/fd/x", "its", "args"])
untuk menghindari kondisi balapan (dalam hal ini $0
akan berisi /dev/fd/x
).
Sekarang, Anda mungkin berpendapat bahwa itu /dev/fd/x
adalah jalan menuju skrip itu. Namun perhatikan bahwa jika Anda membaca dari $0
, Anda akan merusak skrip saat Anda mengkonsumsi input.
Sekarang, ada perbedaan jika nama perintah skrip yang dipanggil tidak mengandung garis miring. Di:
the-script its args
Shell Anda akan mencari the-script
di $PATH
. $PATH
mungkin berisi jalur absolut atau relatif (termasuk string kosong) ke beberapa direktori. Misalnya, jika $PATH
berisi /bin:/usr/bin:
dan the-script
ditemukan di direktori saat ini, shell akan melakukan:
exec("the-script", ["the-script", "its", "args"])
yang akan menjadi:
exec("/bin/sh", ["/bin/sh" or "the-script", "-", "the-script", "its", "args"]
Atau jika ditemukan di /usr/bin
:
exec("/usr/bin/the-script", ["the-script", "its", "args"])
exec("/bin/sh", ["/bin/sh" or "the-script" or "/usr/bin/the-script",
"-", "/usr/bin/the-script", "its", "args")
Dalam semua kasus di atas kecuali kasus sudut setuid, $0
akan berisi path (absolut atau relatif) ke skrip.
Sekarang, skrip juga bisa disebut sebagai:
the-interpreter the-script its args
Ketika the-script
seperti di atas tidak mengandung karakter garis miring, perilaku sedikit berbeda dari shell ke shell.
ksh
Implementasi AT&T lama benar-benar mencari skrip tanpa syarat di $PATH
(yang sebenarnya adalah bug dan lubang keamanan untuk skrip setuid), jadi $0
sebenarnya tidak mengandung jalur ke skrip kecuali $PATH
pencarian benar-benar ditemukan the-script
di direktori saat ini.
AT&T yang lebih baru ksh
akan mencoba dan menafsirkan the-script
dalam direktori saat ini jika itu dapat dibaca. Jika tidak akan mencari yang dapat dibaca dan dieksekusi the-script
di $PATH
.
Karena bash
, ia memeriksa apakah the-script
ada di direktori saat ini (dan bukan merupakan symlink yang rusak) dan jika tidak, cari yang dapat dibaca (belum tentu dapat dieksekusi) the-script
di $PATH
.
zsh
dalam sh
emulasi akan melakukan seperti bash
kecuali bahwa jika the-script
symlink rusak di direktori saat ini, itu tidak akan mencari the-script
in $PATH
dan malah akan melaporkan kesalahan.
Semua kerang mirip Bourne lainnya tidak terlihat the-script
masuk $PATH
.
Untuk semua kerang itu, jika Anda menemukan yang $0
tidak mengandung a /
dan tidak dapat dibaca, maka itu mungkin telah dicari $PATH
. Kemudian, karena file-file di $PATH
dalamnya kemungkinan dapat dieksekusi, mungkin ini perkiraan yang aman untuk digunakan command -v -- "$0"
untuk menemukan jalurnya (meskipun itu tidak akan berhasil jika $0
kebetulan juga merupakan nama dari shell builtin atau kata kunci (dalam kebanyakan shell)).
Jadi, jika Anda benar-benar ingin menutupi kasus itu, Anda bisa menulisnya:
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}""; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
(yang ""
ditambahkan $PATH
adalah untuk melestarikan elemen kosong yang tertinggal dengan cangkang yang $IFS
bertindak sebagai pembatas bukannya pemisah ).
Sekarang, ada lebih banyak cara esoteris untuk menjalankan skrip. Orang bisa melakukan:
the-shell < the-script
Atau:
cat the-script | the-shell
Dalam hal ini, $0
akan menjadi argumen pertama ( argv[0]
) yang diterima penerjemah (di atas the-shell
, tetapi bisa berupa apa saja meskipun umumnya baik nama dasar atau satu jalur ke penerjemah itu).
Mendeteksi bahwa Anda berada dalam situasi itu berdasarkan nilai $0
tidak dapat diandalkan. Anda bisa melihat output ps -o args= -p "$$"
untuk mendapatkan petunjuk. Dalam kasus pipa, tidak ada cara nyata Anda bisa kembali ke jalur ke skrip.
Orang juga bisa melakukan:
the-shell -c '. the-script' blah blih
Kemudian, kecuali dalam zsh
(dan beberapa implementasi lama dari Bourne shell), $0
akan blah
. Sekali lagi, sulit untuk mendapatkan jalan naskah di shell tersebut.
Atau:
the-shell -c "$(cat the-script)" blah blih
dll.
Untuk memastikan Anda memiliki hak $progname
, Anda dapat mencari string tertentu di dalamnya seperti:
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}:; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
[ -f "$progname" ] && grep -q 7YQLVVD3UIUDTA32LSE8U9UOHH < "$progname" ||
progname=unknown
Tetapi sekali lagi saya tidak berpikir itu sepadan dengan usaha.
$0
ada sesuatu selain naskah, yang memang menjawab judul pertanyaan. Namun, saya juga tertarik pada situasi di mana$0
skrip itu sendiri, tetapi tidak termasuk direktori. Secara khusus, saya mencoba memahami komentar yang dibuat pada jawaban SO.