У найпоширеніших випадках $0буде містити шлях, абсолютний або відносно сценарію, так
script_path=$(readlink -e -- "$0")
(якщо припустити, що є readlinkкоманда і вона підтримується -e), як правило, досить хороший спосіб отримати канонічний абсолютний шлях до сценарію.
$0 призначається з аргументу із зазначенням сценарію, переданого інтерпретатору.
Наприклад, у:
the-shell -shell-options the/script its args
$0отримує the/script.
Під час запуску:
the/script its args
Ваша оболонка виконає:
exec("the/script", ["the/script", "its", "args"])
Якщо, наприклад, скрипт містить #! /bin/sh -she-bang, система перетворить це на:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "the/script", "its", "args"])
(якщо він не містить she-bang, або загалом, якщо система повертає помилку ENOEXEC, то ваша оболонка буде робити те саме)
Існує виняток для встановлених / setgid-скриптів у деяких системах, де система відкриє сценарій на деяких fd xі запускає замість цього:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "/dev/fd/x", "its", "args"])
щоб уникнути перегонових умов (у цьому випадку вони $0будуть міститись /dev/fd/x).
Тепер ви можете стверджувати, що /dev/fd/x це шлях до цього сценарію. Однак зауважте, що якщо ви читаєте з $0, ви зламаєте сценарій під час споживання вводу.
Тепер є різниця, якщо ім'я команди скрипта як викликане не містить косу рису. В:
the-script its args
Ваша оболонка буде шукати the-scriptв $PATH. $PATHможе містити абсолютні або відносні (включаючи порожній рядок) шляхи до деяких каталогів. Наприклад, якщо він $PATHміститься /bin:/usr/bin:і the-scriptзнаходиться в поточному каталозі, оболонка виконає:
exec("the-script", ["the-script", "its", "args"])
що стане:
exec("/bin/sh", ["/bin/sh" or "the-script", "-", "the-script", "its", "args"]
Або якщо він знайдений у /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")
У всіх цих випадках, окрім встановленого кутового регістру, $0буде містити шлях (абсолютний або відносний) до сценарію.
Тепер сценарій також можна назвати так:
the-interpreter the-script its args
Якщо, the-scriptяк зазначено вище, символи косого рису не містять, поведінка трохи змінюється від оболонки до оболонки.
Старі реалізації AT&T kshнасправді шукали скрипт беззастережно в $PATH(який насправді був помилкою та захищеним отвором для встановлених сценаріїв), тому $0насправді не містив шлях до сценарію, якщо $PATHпошук фактично не трапився the-scriptв поточному каталозі.
Новіші AT&T kshнамагаються інтерпретувати the-scriptв поточному каталозі, якщо вони читаються. Якщо ні, то він знайде для читабельного та виконуваного файлу the-script в $PATH.
Бо bashвін перевіряє, чи the-scriptзнаходиться в поточному каталозі (а чи не є розірваним символьним посиланням), а якщо ні, шукає читабельний (не обов’язково виконуваний) the-scriptв $PATH.
zshв shемуляції хотілося б bashза винятком того, що якщо the-scriptв поточному каталозі є порушена символьна посилання, вона не шукатиме the-scriptв $PATHі замість цього повідомляє про помилку.
Всі інші Bourne-подібні снаряди не дивляться the-scriptв $PATH.
Для всіх цих оболонок у будь-якому випадку, якщо ви виявите, що $0він не містить /та не читабельний, то він, ймовірно, знайдений $PATH. Тоді, оскільки файли в $PATH, ймовірно, будуть виконуваними, можливо, це безпечне наближення, щоб command -v -- "$0"знайти його шлях (хоча це не буде працювати, якщо $0трапиться також ім'я вбудованої оболонки або ключове слово (у більшості оболонок)).
Тож якщо ви справді хочете прикрити цей випадок, можете написати його:
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
(The ""додаються до $PATHє збереження косого порожнього елемента з оболонками, $IFSдіє як роздільник замість роздільник ).
Тепер є більше езотеричних способів викликати сценарій. Можна зробити:
the-shell < the-script
Або:
cat the-script | the-shell
У такому випадку $0буде першим аргументом ( argv[0]), який отримав інтерпретатор (вище the-shell, але це може бути що-небудь, хоча загалом або базове ім'я, або один шлях до цього перекладача).
Виявлення того, що ви знаходитесь у цій ситуації на основі значення $0, не є надійним. Ви можете подивитися на висновок, ps -o args= -p "$$"щоб отримати підказку. У випадку "pipe" немає реального способу повернутися до шляху до сценарію.
Можна також зробити:
the-shell -c '. the-script' blah blih
Тоді, крім zsh(і деякої старої реалізації оболонки Борна), $0було б blah. Знову ж таки, важко потрапити на шлях сценарію в тих оболонках.
Або:
the-shell -c "$(cat the-script)" blah blih
тощо.
Щоб переконатися, що ви маєте право $progname, ви можете шукати в ньому певний рядок, наприклад:
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
Але знову ж таки я не думаю, що варто важити зусиль.
$0щось інше, ніж сценарій, що відповідає назви питання. Однак мене також цікавлять ситуації, коли$0є сам сценарій, але він не включає каталог. Зокрема, я намагаюся зрозуміти коментар, зроблений у відповіді на ЗО.