Во всех отношениях, типичным современным дистрибутивом Linux (Ubuntu, Debian, Red Hat, Fedora, Slackware, и т.д.) является Unix, но строго говоря, никакая система не может утверждать, что была Unix без того, чтобы быть сертифицированным, таким образом, вместо этого люди говорят, что они подобны Unix. Они вдохновлены Unix и продолжают его культуру.
Это также относится к системам BSD.
Mac OS X является сертифицированный Unix, таким образом, это - Unix и на имя и действительно. (и это на самом деле основано на BSD).
Нужно отметить, что, так как сам Linux является просто ядром, это может использоваться для создания неподобных Unix систем (таких как Android).
В tcsh
, $_
в начале сценария будет содержать местоположение, если файл был получен и $0
содержит его, если это было выполнено.
#!/bin/tcsh
set sourced=($_)
if ("$sourced" != "") then
echo "sourced $sourced[2]"
endif
if ("$0" != "tcsh") then
echo "run $0"
endif
В Bash:
#!/bin/bash
[[ $0 != $BASH_SOURCE ]] && echo "Script is being sourced" || echo "Script is being run"
Я думаю, что Вы могли использовать $BASH_SOURCE
переменная. Это возвращает путь, который выполнялся:
pbm@tauri ~ $ /home/pbm/a.sh
/home/pbm/a.sh
pbm@tauri ~ $ ./a.sh
./a.sh
pbm@tauri ~ $ source /home/pbm/a.sh
/home/pbm/a.sh
pbm@tauri ~ $ source ./a.sh
./a.sh
Таким образом на следующем шаге мы должны проверить, относителен ли путь или нет. Если это не относительно, все в порядке. Если это, мы могли бы проверить путь с pwd
, конкатенируйте с /
и $BASH_SOURCE
.
source
поиски в $PATH
если имя не содержит a /
. Поисковый порядок зависит от опций оболочки, обратитесь к руководству для деталей.
– Gilles 'SO- stop being evil'
08.12.2010, 21:09
mydir="$(cd "$(dirname "$BASH_SOURCE")"; pwd)"
работал бы?
– Kevin Cantu
08.12.2010, 21:36
Это решение относится только к башу, а не к tcsh. Обратите внимание, что обычно поставляемый ответ ${BASH_SOURCE[0]}
не будет работать, если попытаться найти путь изнутри функции.
Я нашел эту строку, чтобы всегда работать, независимо от того, исходит ли файл или запускается в качестве скрипта.
echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
Если вы хотите следовать по симлинкам, используйте readlink
на пути, который вы получаете выше, рекурсивно или не рекурсивно.
Вот скрипт, чтобы попробовать его и сравнить с другими предложенными решениями. Вызовите его как source test1/test2/test_script.sh
или bash test1/test2/test_script.sh
.
#
# Location: test1/test2/test_script.sh
#
echo $0
echo $_
echo ${BASH_SOURCE}
echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
cur_file="${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
cur_dir="$(dirname "${cur_file}")"
source "${cur_dir}/func_def.sh"
function test_within_func_inside {
echo ${BASH_SOURCE}
echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
}
echo "Testing within function inside"
test_within_func_inside
echo "Testing within function outside"
test_within_func_outside
#
# Location: test1/test2/func_def.sh
#
function test_within_func_outside {
echo ${BASH_SOURCE}
echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
}
Причина, по которой работает один лайнер, объясняется использованием переменной окружения BASH_SOURCE
и ее ассоциированной FUNCNAME
.
BASH_SOURCE
Переменная массива, членами которой являются имена исходных файлов, в которых определены соответствующие имена функций оболочки в переменной массива FUNCNAME. Функция оболочки ${FUNCNAME[$i]} определена в файле ${BASH_SOURCE[$i]} и вызывается из ${BASH_SOURCE[$i+1]}.
FUNCNAME
- переменная массива, содержащая имена всех функций оболочки, находящихся в стеке вызовов выполнения. Элемент с индексом 0 является именем любой выполняемой в данный момент функции оболочки. Самый нижний элемент (элемент с наибольшим индексом) является "главным". Эта переменная существует только при выполнении функции оболочки. Присвоения FUNCNAME не имеют никакого эффекта и возвращают статус ошибки. Если FUNCNAME не установлено, то она теряет свои специальные свойства, даже если впоследствии сбрасывается.
Эту переменную можно использовать с BASH_LINENO и BASH_SOURCE. Каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, из файла ${BASH_SOURCE[$i+1]} по номеру строки ${BASH_LINENO[$i]} был вызван ${FUNCNAME[$i]}. Встроенный вызывающий абонент отображает текущий стек вызовов, используя эту информацию.
[Источник: Бэш-руководство]
Для тщательности и пользы искателей, вот то, что они делают... Это - общественная Wiki, поэтому не стесняйтесь добавлять эквиваленты другой оболочки (очевидно, $BASH_SOURCE будет отличаться).
test.sh:
#! /bin/sh
called=$_
echo $called
echo $_
echo $0
echo $BASH_SOURCE
test2.sh:
#! /bin/sh
source ./test.sh
$./test2.sh
./test2.sh
./test2.sh
./test2.sh
./test.sh
$ sh ./test2.sh
/bin/sh
/bin/sh
./test2.sh
./test.sh
$./test2.sh
./test2.sh
./test2.sh
./test2.sh
$/bin/sh ./test2.sh
/bin/sh
/bin/sh
./test2.sh
$
$ ./test2.sh
./test.sh
./test.sh
./test.sh
$ zsh test.sh
echo
test.sh
$
called=$_; echo $called; echo $_
? Не будет эта печать $_
дважды?
– Ciro Santilli 新疆改造中心法轮功六四事件
14.09.2014, 10:17
$_
специальный параметр: "При запуске оболочки набор к абсолютному пути раньше вызывал сценарий оболочки или сценарий оболочки, выполняемый, как передано в среде или списке аргументов. Впоследствии, расширяется до последнего аргумента предыдущей команде, после расширения. Также набор к полному пути раньше вызывал каждую команду, выполняемую и помещенную в среду, экспортируемую в ту команду. При проверке почты этот параметр содержит название почтового файла".
– Adam Rosenfield
17.09.2014, 22:14
На самом деле, "dirname 0$" получит Вас путь к сценарию, но необходимо интерпретировать его немного:
$ cat bash0
#!/bin/bash
echo \$0=$0
dirname $0
$ bash0 # "." appears in PATH right now.
$0=./bash0
.
$ ./bash0
$0=./bash0
.
$ $PWD/bash0
$0=/home/00/bediger/src/ksh/bash0
/home/00/bediger/src/ksh
$ $PWD/../ksh/bash0
$0=/home/00/bediger/src/ksh/../ksh/bash0
/home/00/bediger/src/ksh/../ksh
$ ../ksh/bash0
$0=../ksh/bash0
../ksh
Необходимо подготовиться обрабатывать "." как имя каталога при некоторых общих обстоятельствах. Я экспериментировал бы немного, поскольку я помню dirname встроенное к ksh выполнение вещей немного по-другому, когда"." появляется в ПУТИ.
$0
просто содержит "удар" для интерактивной оболочки, и это - весь полученный сценарий, видит.
– Cascabel
08.12.2010, 18:32
Для оболочки удара я нашел ответ @Dennis Williamson самым полезным, но это не работало в случае sudo
. Это делает:
if ( [[ $_ != $0 ]] && [[ $_ != $SHELL ]] ); then
echo "I'm being sourced!"
exit 1
fi
У меня это сработало в bash, dash, ksh и zsh:
if test -n "$BASH" ; then script=$BASH_SOURCE
elif test -n "$TMOUT"; then script=${.sh.file}
elif test -n "$ZSH_NAME" ; then script=${(%):-%x}
elif test ${0##*/} = dash; then x=$(lsof -p $$ -Fn0 | tail -1); script=${x#n}
else script=$0
fi
echo $script
Вывод для этих оболочек:
BASH source: ./myscript
ZSH source: ./myscript
KSH source: /home/pbrannan/git/theme/src/theme/web/myscript
DASH source: /home/pbrannan/git/theme/src/theme/web/myscript
BASH: ./myscript
ZSH: ./myscript
KSH: /home/pbrannan/git/theme/src/theme/web/myscript
DASH: ./myscript
Я попытался заставить его работать для csh / tcsh, но это слишком сложно; Я придерживаюсь POSIX.
Меня немного смутил вики-ответ сообщества (от Шона Дж. Гоффа ), поэтому я написал сценарий, чтобы разобраться во всем. О $_
я нашел это:Использование _
в качестве переменной среды, переданной команде . Это переменная среды, поэтому ее значение легко проверить неправильно.
Ниже приведен скрипт, затем его вывод. Они также находятся в этой сути .
#!/bin/bash
# test-shell-default-variables.sh
# Usage examples (you might want to `sudo apt install zsh ksh`):
#
# ./test-shell-default-variables.sh dash bash
# ./test-shell-default-variables.sh dash bash zsh ksh
# ./test-shell-default-variables.sh dash bash zsh ksh | less -R
# `-R` in `less -R` to have less pass escape sequences directly to the terminal
# so we have colors.
# The "invoking with name `sh`" tests are commented because for every shell I
# tested (dash, bash, zsh and ksh), the output was the same as that of dash.
# The `test_expression` function also work with expansion changes. You can try
# lines like `test_expression '{BASH_SOURCE:-$0}'`.
echolor() {
echo -e "\e[1;36m$@\e[0m"
}
tell_file() {
echo File \`"$1"\` is:
echo \`\`\`
cat "$1"
echo \`\`\`
echo
}
SHELL_ARRAY=("$@")
test_command() {
for shell in "${SHELL_ARRAY[@]}"
do
prepare "$shell"
cmd="$(eval echo $1)"
# echo "cmd: $cmd"
printf '%-4s: ' "$shell"
{ env -i $cmd 2>&1 1>&3 | sed 's/^/[err]/'; } 3>&1
teardown
done
echo
}
prepare () {
shell="$1"
PATH="$PWD/$shell/sh:$PATH"
}
teardown() {
PATH="${PATH#*:}"
}
###
### prepare
###
for shell in "${SHELL_ARRAY[@]}"
do
mkdir "$shell"
ln -sT "/bin/$shell" "$shell/sh"
done
echo > printer.sh
echo '../printer.sh' > sourcer.sh
rm linked.sh &>/dev/null; ln -sT "printer.sh" "linked.sh"
tell_file sourcer.sh
###
### run
###
test_expression() {
local expr="$1"
# prepare
echo "echo $expr" > printer.sh
tell_file printer.sh
# run
cmd='$shell./printer.sh'
echolor "\`$cmd\` (simple invocation) ($expr):"
test_command "$cmd"
# cmd='sh./printer.sh'
# echolor "\`$cmd\` (when executable name is \`sh\`) ($expr):"
# test_command "$cmd"
cmd='$shell./sourcer.sh'
echolor "\`$cmd\` (via sourcing) ($expr):"
test_command "$cmd"
# cmd='sh./sourcer.sh'
# echolor "\`$cmd\` (via sourcing, when name is \`sh\`) ($expr):"
# test_command "$cmd"
cmd='$shell./linked.sh'
echolor "\`$cmd\` (via symlink) ($expr):"
test_command "$cmd"
# cmd='sh./linked.sh'
# echolor "\`$cmd\` (via symlink, when name is \`sh\`) ($expr):"
# test_command "$cmd"
echolor "------------------------------------------"
echo
}
test_expression '$BASH_SOURCE'
test_expression '$0'
test_expression '$(/bin/true x y; true a b c; echo $_)' # Rq: true is a builtin
test_expression '$_'
###
### teardown
###
for shell in "${SHELL_ARRAY[@]}"
do
rm "$shell/sh"
rm -d "$shell"
done
rm sourcer.sh
rm linked.sh
rm printer.sh
./test-shell-default-variables.sh {da,ba,z,k}sh
File `sourcer.sh` is:
```
../printer.sh
```
File `printer.sh` is:
```
echo $BASH_SOURCE
```
`$shell./printer.sh` (simple invocation) ($BASH_SOURCE):
dash:
bash:./printer.sh
zsh :
ksh :
`$shell./sourcer.sh` (via sourcing) ($BASH_SOURCE):
dash:
bash:./printer.sh
zsh :
ksh :
`$shell./linked.sh` (via symlink) ($BASH_SOURCE):
dash:
bash:./linked.sh
zsh :
ksh :
------------------------------------------
File `printer.sh` is:
```
echo $0
```
`$shell./printer.sh` (simple invocation) ($0):
dash:./printer.sh
bash:./printer.sh
zsh :./printer.sh
ksh :./printer.sh
`$shell./sourcer.sh` (via sourcing) ($0):
dash:./sourcer.sh
bash:./sourcer.sh
zsh :./printer.sh
ksh :./sourcer.sh
`$shell./linked.sh` (via symlink) ($0):
dash:./linked.sh
bash:./linked.sh
zsh :./linked.sh
ksh :./linked.sh
------------------------------------------
File `printer.sh` is:
```
echo $(/bin/true x y; true a b c; echo $_)
```
`$shell./printer.sh` (simple invocation) ($(/bin/true x y; true a b c; echo $_)):
dash:
bash: c
zsh : c
ksh :
`$shell./sourcer.sh` (via sourcing) ($(/bin/true x y; true a b c; echo $_)):
dash:
bash: c
zsh : c
ksh :
`$shell./linked.sh` (via symlink) ($(/bin/true x y; true a b c; echo $_)):
dash:
bash: c
zsh : c
ksh :
------------------------------------------
File `printer.sh` is:
```
echo $_
```
`$shell./printer.sh` (simple invocation) ($_):
dash:
bash: bash
zsh :
ksh :
`$shell./sourcer.sh` (via sourcing) ($_):
dash:
bash: bash
zsh :./printer.sh
ksh :
`$shell./linked.sh` (via symlink) ($_):
dash:
bash: bash
zsh :
ksh :
------------------------------------------
$BASH_SOURCE
$BASH_SOURCE
работает в bash и только в bash. $0
заключается в том, что текущий файл был получен другой файл. В таком случае,$BASH_PROFILE
содержит имя исходный файл, а не исходный файл. $0
$0
имеет то же значение, что и $BASH_SOURCE
в bash. $_
$_
остается нетронутым тире и ksh. $_
затухает до последнего аргумента последнего вызова. $_
как "bash". $_
нетронутым. (при поиске это `просто результат правила «последнего аргумента» ). sh
, в отношении этих тестов они ведут себя как dash. tl;drscript=$(readlink -e -- "${BASH_SOURCE}")
(для bash очевидно)
$BASH_SOURCE
тестовые примеры данный файл/tmp/source1.sh
echo '$BASH_SOURCE '"(${BASH_SOURCE})"
echo 'readlink -e $BASH_SOURCE'\
"($(readlink -e -- "${BASH_SOURCE}"))"
source
файл разными способами
source
из/tmp
$> cd /tmp
$> source source1.sh
$BASH_SOURCE (source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
$> source./source1.sh
$BASH_SOURCE (./source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
$> source /tmp/source1.sh
$BASH_SOURCE (/tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
source
из/
cd /
$> source /tmp/source1.sh
$0 (bash)
$BASH_SOURCE (/tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
source
из разных относительных путей /tmp/a
и/var
$> cd /tmp/a
$> source../source1.sh
$BASH_SOURCE (../source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
$> cd /var
$> source../tmp/source1.sh
$BASH_SOURCE (../tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
$0
во всех случаях, если в скрипт добавлена команда
echo '$0 '"(${0})"
затем source
скрипт всегда печатается
$0 (bash)
однако , если скрипт был запустить , например.
$> bash /tmp/source1.sh
, тогда $0
будет строковым значением /tmp/source1.sh
.
$0 (/tmp/source1.sh)
$BASH_SOURCE (/tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
этот ответ описывает, как lsof
и немного магии grep — единственное, что, кажется, имеет шанс работать с вложенными исходными файлами под tcsh:
/usr/sbin/lsof +p $$ | grep -oE /.\*source_me.tcsh
wdir="$PWD"; [ "$PWD" = "/" ] && wdir=""
case "$0" in
/*) scriptdir="${0%/*}";;
*) scriptdir="$wdir/${0#./}"; scriptdir="${scriptdir%/*}";;
esac
echo "$scriptdir"
Возможно, это не будет работать с символическими ссылками или исходными файлами, но будет работать с обычными файлами. Взято за ссылку отсюда. @кенорб Нет имени каталога, ссылка для чтения, BASH _SOURCE.
Самая сложная часть заключается в том, чтобы найти текущий исходный файл для оболочки dash, используемой в качестве замены sh в Ubuntu. Следующий фрагмент кода можно использовать в исходном скрипте, чтобы определить его абсолютный путь. Протестировано в bash, zsh и dash, вызываемых как dash, так и sh.
NB :зависит от современной утилиты realpath (1)из пакета GNU coreutils
NB :lsof (1 )варианты также должны быть проверены, потому что аналогичные советы как с этой, так и с других страниц не работали для меня в Ubuntu 18 и 19, поэтому мне пришлось изобретать это заново.
getShellName() {
[ -n "$BASH" ] && echo ${BASH##/*/} && return
[ -n "$ZSH_NAME" ] && echo $ZSH_NAME && return
echo ${0##/*/}
}
getCurrentScript() {
local result
case "$(getShellName)" in
bash ) result=${BASH_SOURCE[0]}
;;
zsh ) emulate -L zsh
result=${funcfiletrace[1]%:*}
;;
dash | sh )
result=$(
lsof -p $$ -Fn \
| tail --lines=1 \
| xargs --max-args=2 \
| cut --delimiter=' ' --fields=2
)
result=${result#n}
;;
* ) result=$0
;;
esac
echo $(realpath $result)
}
Если вам нужен абсолютный путь к каталогу, содержащему скрипт, вы можете использовать этот фрагмент:
BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]:-$0}" )" >/dev/null 2>&1 && pwd )"
Если вам нужен только относительный путь к скрипту:
SCRIPT_PATH="${BASH_SOURCE[0]:-$0}"
Эти фрагменты должны работать на разных версиях bash и zsh.
Я использую приведенный выше код, чтобы получить путь к исходному файлу bash:
$(readlink -f ${BASH_SOURCE[0]})
> tcsh --version\n tcsh 6.14.00 (Astron) 2005-03-25 (i486-intel-linux) options wide,nls,dl,al,kan,rh,nd,color,filec
. До определения источника его нев интерактивном режиме, исходный файл включен в родительский файл, как будто это была на самом деле часть его (неразличимо так), как Вы упоминаете в своем исходном вопросе. Я думаю, что Ваше позиционное обходное решение параметра является, вероятно, лучшим подходом. Однако обычный вопрос, "почему делают Вы хотите сделать, это" и обычный ответ на ответ, "не делают, это - делает это вместо этого", где "это" должно часто хранить... – Paused until further notice. 10.05.2011, 18:33.
иsource
работавший тождественно в этом отношении. Отметьте это$_
должен быть получен доступ в первом операторе в файле, иначе он будет содержать последний аргумент предыдущей команды. Мне нравится включать хижину для моей собственной ссылки, таким образом, я знаю то, что окружает, она, как предполагается, для и для редактора, таким образом, она использует подсветку синтаксиса. – Paused until further notice. 04.03.2013, 13:51source
, затем выполнение.
. Я приношу извинения за то, что был некомпетентен. Они действительно идентичны. Так или иначе,$BASH_SOURCE
работы. – clacke 05.03.2013, 09:35