У меня есть следующий код в моем 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...?
и посмотрим на всю замечательную информацию, которую мы можем получить, и мы идем, откуда мы пришли.
ура!