Расположение исходного сценария недоступно, если вы не используете оболочку, которая предлагает расширения для спецификации POSIX. Вы можете проверить это с помощью следующего фрагмента:
env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included
где included.sh
содержится
echo "$0"
set
В bash имя исходного сценария находится в $BASH_SOURCE
. В zsh (в режиме совместимости с zsh, а не в режиме совместимости с sh или ksh) он находится в $0
(обратите внимание, что в $0
функции вместо этого используется имя функции). В pdksh и dash он недоступен. В ksh93 этот метод не раскрывает решение, но полный путь к включенному сценарию доступен как ${.sh.file}
.
Если вам требуется bash, ksh93 или zsh, вы можете использовать этот фрагмент:
if [ -n "$BASH_SOURCE" ]; then
this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
setopt function_argzero
this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
eval 'this_script=${.sh.file}'
else
echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
exit 2
fi
Вы можете попытаться угадать местоположение скрипта, посмотрев, какие файлы открыта оболочкой. Экспериментально это работает с dash и pdksh, но не с bash или ksh93, которые, по крайней мере для короткого скрипта, закрыли файл скрипта к тому времени, когда им удалось его выполнить.
open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
if [ -n "$open_file" ]; then
# best guess: $open_file is this script
fi
Сценарий может не являться файлом с дескриптором с наибольшим номером, если сценарий получен из сложного сценария, который воспроизводит перенаправления. Вы можете циклически просматривать открытые файлы. Это не гарантировано работать в любом случае. Единственный надежный способ найти исходный скрипт - это использовать bash, ksh93 или zsh.
Если вы можете изменить интерфейс, то вместо того, чтобы использовать свой сценарий, пусть ваш сценарий распечатает фрагмент оболочки, который будет передан eval
вызывающей стороне. Это то, что обычно делают скрипты для установки переменных среды. Это позволяет вашему сценарию быть написанным независимо от капризов оболочки вызывающего абонента и конфигурации оболочки.
#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF
В звонилке: eval "`/path/to/setenv`"