У меня есть следующий код в моем bash script. Теперь я хочу использовать его в POSIX sh. Итак, как его преобразовать? Благодарю.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
У меня есть следующий код в моем bash script. Теперь я хочу использовать его в POSIX sh. Итак, как его преобразовать? Благодарю.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
Оболочка POSIX-оболочки (sh) $BASH_SOURCE равна $0. см. снизу для справочной информации
Предостережение. Важным отличием является то, что , если ваш script находится в исходной оболочке с .), снизу ниже не будет работать должным образом. ниже ниже
Обратите внимание, что в приведенных ниже фрагментах я изменил DIR на DIR, потому что он лучше не использовать имена переменных с прописными буквами, чтобы избежать столкновений с переменными среды и специальными переменными оболочки.
Префикс CDPATH= заменяет > /dev/null в исходной команде: $CDPATH устанавливается в пустую строку, чтобы гарантировать, что cd никогда не будет эхом ничего.
В простейшем случае это будет (эквивалент команды OP):
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
Если вы также хотите разрешить результирующий путь каталога к своей конечной цели, если каталог и/или его компоненты являются символическими ссылками, добавьте -P в команду pwd:
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
Предостережение. Это НЕ так же, как поиск script собственного исходного каталога происхождения:
Скажем, ваш script foo символически связан с /usr/local/bin/foo в $PATH, но его истинный путь /foodir/bin/foo.
Вышеописанное будет сообщать /usr/local/bin, поскольку разрешение символьной ссылки (-P) применяется к каталогу /usr/local/bin, а не к самому script.
Чтобы найти собственный каталог script исходного каталога, вам нужно будет проверить путь script, чтобы увидеть, является ли он символической ссылкой и, если да, следуйте (цепочка ) символических ссылок на конечный файл цели, а затем извлечь путь к каталогу из канонического пути целевого файла.
GNU readlink -f (лучше: readlink -e) может сделать это для вас, но readlink не является утилитой POSIX.
Хотя на платформах BSD, включая OSX, есть утилита readlink, а на OSX она не поддерживает функциональность -f. Тем не менее, чтобы показать, насколько проста задача, если readlink -f доступен: dir=$(dirname "$(readlink -f -- "$0")").
На самом деле существует нет утилиты POSIX для разрешения символических ссылок на файлы. Есть способы обойти это, но они громоздки и не полностью надежны:
следующая, совместимая с POSIX функция оболочки реализует то, что GNU readlink -e делает, и является <сильным > достаточно надежным решением, которое работает только в двух случаях с редким краем
-> (также редко)С помощью этой функции, названной rreadlink, определенной, , определяется путь script истинного каталога происхождения:
dir=$(dirname -- "$(rreadlink "$0")")
rreadlink() исходный код - место перед вызовами в скриптах:
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.
target=$1 fname= targetDir= CDPATH=
# Try to make the execution environment as predictable as possible:
# All commands below are invoked via `command`, so we must make sure that `command`
# itself is not redefined as an alias or shell function.
# (Note that command is too inconsistent across shells, so we don't use it.)
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not even have
# an external utility version of it (e.g, Ubuntu).
# `command` bypasses aliases and shell functions and also finds builtins
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for that
# to happen.
{ \unalias command; \unset -f command; } >/dev/null 2>&1
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.
while :; do # Resolve potential symlinks until the ultimate target is found.
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
fname=$(command basename -- "$target") # Extract filename.
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
if [ -L "$fname" ]; then
# Extract [next] target path, which may be defined
# *relative* to the symlink own directory.
# Note: We parse `ls -l` output to find the symlink target
# which is the only POSIX-compliant, albeit somewhat fragile, way.
target=$(command ls -l "$fname")
target=${target#* -> }
continue # Resolve [next] symlink target.
fi
break # Ultimate target reached.
done
targetDir=$(command pwd -P) # Get canonical dir. path
# Output the ultimate target canonical path.
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
if [ "$fname" = '.' ]; then
command printf '%s\n' "${targetDir%/}"
elif [ "$fname" = '..' ]; then
# Caveat: something like /var/.. will resolve to /private (assuming /[email protected] -> /private/var), i.e. the '..' is applied
# AFTER canonicalization.
command printf '%s\n' "$(command dirname -- "${targetDir}")"
else
command printf '%s\n' "${targetDir%/}/$fname"
fi
)
Чтобы быть надежным и предсказуемым, функция использует command, чтобы гарантировать, что вызываются только встроенные оболочки или внешние утилиты (игнорирует перегрузки в формах псевдонимов и функций).
Он тестировался в последних версиях следующих оболочек: bash, dash, ksh, zsh.
tl; dr:
Использование только функций POSIX:
zsh, который, однако, обычно не действует как sh).$0 с исполняемым именем/контуром оболочки (кроме zsh, где, как отмечено $0, действительно является текущим script). Напротив (кроме zsh), script был получен из другого script, который сам был вызван непосредственно, содержит этот путь script в $0.bash, ksh и zsh имеют нестандартные функции, которые позволяют определять фактический путь script даже в сценариях с исходными кодами, а также определять, w370 > является источником или нет; например, в bash, $BASH_SOURCE всегда содержит пробег script, независимо от того, является ли он источником или нет, а [[ $0 != "$BASH_SOURCE" ]] может использоваться для проверки того, будет ли источник script отправлен.Чтобы показать, почему это невозможно сделать, проанализируйте команду ответ Уолтера:
# NOT recommended - see discussion below.
DIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
-P дважды избыточно - достаточно использовать его с pwd.cd потенциала stdout, если $CDPATH устанавливается.)command -v -- "$0"
command -v -- "$0" предназначен для покрытия одного дополнительного сценария: если script получается из интерактивной оболочки, $0 обычно содержит простое имя исполняемого файла оболочки (sh), и в этом случае dirname просто вернет . (потому что то, что dirname неизменно делает, когда задан аргумент без компонента пути).
command -v -- "$0" затем возвращает этот абсолютный путь оболочки через поиск $PATH (/bin/sh). Обратите внимание, однако, что в командах для входа на некоторых платформах (например, OSX) есть имя файла с префиксом - в $0 (-sh), и в этом случае command -v -- "$0" не работает должным образом (возвращает пустую строку).command -v -- "$0" может ошибочно работать в двух сценариях, не относящихся к источникам, в которые непосредственно запускается исполняемый файл оболочки sh, с аргументом script в качестве аргумента:
command -v -- "$0" может возвращать пустую строку, в зависимости от того, какая конкретная оболочка действует как sh для данной системы: bash, ksh и zsh return пустая строка; только dash эхо-сигналы $0 command явно не указано, должен ли command -v при применении к пути файловой системы возвращать только исполняемые файлы - это то, что bash, ksh и zsh do - но вы может утверждать, что это подразумевается самой целью command; Любопытно, что dash, который обычно является наиболее совместимым гражданином POSIX, отклоняется от стандарта здесь. Напротив, ksh является единственным гражданином модели здесь, поскольку он является единственным, который сообщает только исполняемые файлы и сообщает им абсолютный (хотя и не нормированный) путь, как того требует спецификация.$PATH, а вызов использует его простое имя файла (например, sh myScript), command -v -- "$0" также возвращает пустую строку, за исключением dash.$0 затем не содержит эту информацию (кроме zsh, которая обычно не действует как sh) - нет хорошего решения этой проблемы.
$0: [ "$0" = "sh" ] || [ "$0" = "-sh" ] || [ "$0" = "/bin/sh" ]$0 затем просто содержит путь sourcing script.command -v -- "$0" в сценариях источников и тот факт, что он разбивает два сценария, не относящихся к источникам, мой голос за НЕиспользует его, что оставляет нам:
$dir заканчивается либо содержащим ., если исполняемый файл оболочки был вызван как простое имя файла (применение dirname к простому filename всегда возвращает .) или путь к исполняемому каталогу оболочки в противном случае. . не может быть надежно отличен от невостребованного вызова из текущего каталога.$0 содержит этот путь script, а источник script не имеет возможности сообщить, является ли этот случай. POSIX определяет поведение $0 по сценариям оболочки здесь.
По существу, $0 должен отражать путь к файлу script, как указано, что подразумевает:
$0, содержащий абсолютный путь. $0 содержит абсолютный путь, только если:
~/bin/myScript (при условии, что сам script является исполняемым)sh ~/bin/myScript$PATH; за кулисами система преобразует myScript в абсолютный путь и затем выполняет ее; например.:
myScript # executes /home/jdoe/bin/myScript, for instanceВо всех остальных случаях $0 будет отображать путь script , как указано:
sh с script это может быть просто имя файла (например, sh myScript) или относительный путь (например, sh ./myScript)./myScript) - обратите внимание, что простое имя файла найдет только скрипты в $PATH).На практике bash, dash, ksh и zsh проявляют это поведение.
В отличие от POSIX НЕ задает значение $0 при поиске script (используя специальную встроенную утилиту . ( "точка" )), поэтому вы не можете полагаться на него, и на практике поведение отличается от оболочки.
$0, когда ваш script является источником и ожидает стандартизованного поведения.
bash, dash и ksh оставляют $0 нетронутыми при поиске сценариев, что означает, что $0 содержит значение $0 вызывающего абонента или, более точно, значение $0 самого последнего вызывающего абонента в цепочке вызовов, которая не была получена сама по себе; таким образом, $0 может указывать либо на исполняемый файл оболочки, либо на путь другого (непосредственно вызываемого) script, который был источником текущего.zsh, как одиночный диссидент, действительно сообщает текущий путь script в $0. И наоборот, $0 не будет указывать, является ли источник script или нет.$0 к текущий script путь.bash, ksh и zsh все предлагают свои собственные способы получения запущенного пути script, даже если он был создан.Для полноты: значение $0 в других контекстах:
$0 оставался неизменным; поэтому, независимо от того, какое значение оно имеет вне функции, оно также будет внутри.
bash, dash и ksh ведут себя таким образом.zsh является одиночным диссидентом и сообщает имя функции.-c при запуске, это первый операнд (необязательный аргумент), который устанавливает $0; например.:
sh -c 'echo \$0: $0 \$1: $1' foo one # -> '$0: foo $1: one'bash, dash, ksh и zsh все ведут себя таким образом.$0 - это значение первого аргумента, переданного родительским процессом оболочки, как правило, имя или путь оболочки (например, sh или /bin/sh); Это включает:
- к имени оболочки перед тем, как поместить его в $0, чтобы сигнализировать shell, что это оболочка _login; таким образом, по умолчанию $0 сообщает -bash, а не bash, в интерактивных оболочках OSX.sh < myScript)bash, dash, ksh и zsh все ведут себя таким образом.@City ответил, что
DIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )
работает. Я тоже это использовал. Я нашел команду fooobar.com/questions/37598/....
if OLDPWD=/dev/fd/0 \
cd - && ls -lLidFH ?
then cd . <8
fi </proc/self/fd 8<. 9<$0
там. это должно позволить вам изменить directpry через некоторые магические ссылки как дескрипторы файлов.
настройка $OLDPWD pre- cd экспортирует значение для продолжительности один смена каталога (Примечание: cd может иметь остаточные эффекты на hash - таблицах, но только sh, о которых я знаю, что на самом деле мужчин любое хорошее использование из них является Кевин ahlmquists - и так как Герберт Сюй - dash, и, возможно, некоторые вещи bsd, но что я знаю?), но не переносит экспорт cd в результате изменения.
Таким образом, $OLDPWD, на самом деле, не изменяется, и если оно вообще имело какое-либо значение, оно остается таким же, как было. $PWD изменяется в результате первого cd, и значение становится /dev/fd/0 которое указывает на /proc/self/fd, где должен быть список файловых дескрипторов для нашего процесса . , чтобы включить все, что $0 на ./2.
так мы делаем ls...? и посмотрим на всю замечательную информацию, которую мы можем получить, и мы идем, откуда мы пришли.
ура!