我想我可能不太幸运,因为采购导致命令在当前shell中执行,因此
source $script $script
仍然是当前Shell的调用,而不是源脚本。目前,我最好的想法是执行q4312079q,以便第一个位置参数包含必要的信息。任何人都有更好的方法吗?要清楚,我正在采购脚本,而不是运行它:
source foo.bash
#1 楼
在tcsh
中,脚本开头的$_
将包含该位置(如果该文件是源文件),而q4312079q
包含该位置(如果该文件已运行)。/>
#!/bin/tcsh
set sourced=($_)
if ("$sourced" != "") then
echo "sourced $sourced[2]"
endif
if ("#!/bin/bash
[[ q4312078q != $BASH_SOURCE ]] && echo "Script is being sourced" || echo "Script is being run"
" != "tcsh") then
echo "run q4312078q"
endif
评论
我只是有机会在tcsh中使用它,并且注意到没有shebang它将无法正常工作。如果您只是采购而不执行,那么行为改变似乎有些奇怪...
–卡斯卡贝尔
2011年4月20日在16:28
如果脚本是非交互式来源的(例如从cshrc),则tcsh版本似乎也不起作用。在这种情况下,我似乎找不到找到信息的方法。有什么想法吗?
–卡斯卡贝尔
2011年5月9日18:04
采购它对我没有任何影响。 > tcsh --version \ n tcsh 6.14.00(Astron)2005-03-25(i486-intel-linux)选项宽,nls,dl,al,kan,rh,nd,color,filec。至于非交互地采购它,就像您在原始问题中提到的那样,源文件被包含在父文件中,就好像它实际上是它的一部分一样。我认为您的位置参数解决方法可能是最好的方法。但是,通常的问题是“您为什么要这样做”,而答复的通常的答案是“不要这样做-而是这样做”,其中“此”通常存储在...
–丹尼斯·威廉姆森
2011年5月10日15:33
@clacke:我发现从2.05b到4.2.37(包括4.1.9)测试的所有Bash版本中都存在该问题。在这方面,消息来源的工作方式完全相同。请注意,必须在文件的第一条语句中访问$ _,否则它将包含上一条命令的最后一个参数。我喜欢将shebang包括在内以作为我自己的参考,因此我知道它应该用于什么外壳以及用于编辑器,因此它使用语法突出显示。
–丹尼斯·威廉姆森
13年4月4日在11:51
哈哈。显然,我正在通过先进行源测试,然后再进行测试来进行测试。它们确实是相同的。无论如何,$ BASH_SOURCE起作用。
–clacke
2013年5月5日7:35
#2 楼
我认为您可以使用$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
串联。评论
并请注意,如果给定名称不包含/,则源将在$ PATH中搜索。搜索顺序取决于外壳选项,有关详细信息,请参见手册。
–吉尔斯'所以-不再是邪恶的'
2010-12-8 19:09
因此,类似mydir =“ $(cd” $(dirname“ $ BASH_SOURCE”)“; pwd)”的东西可以工作吗?
–凯文·坎图(Kevin Cantu)
2010-12-8 19:36
谢谢,一个快速而有用的答案。丹尼斯(Dennis)也因提供tcsh答案而赢得绿色复选标记。 @Gilles:是的,我确实在文档中找到了。幸运的是,对于我的用例,我几乎不必担心它。
–卡斯卡贝尔
2010-12-8 19:46
#3 楼
此解决方案仅适用于bash,不适用于tcsh。请注意,如果您尝试从函数中查找路径,则通常提供的答案${BASH_SOURCE[0]}
将不起作用。 echo ${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}
如果要跟随符号链接,请在到达的路径上使用
readlink
(递归或非递归)。这里是一个脚本,可以对其进行尝试并将其与其他建议的解决方案进行比较。调用它为
source test1/test2/test_script.sh
或bash test1/test2/test_script.sh
。 BASH_SOURCE
一个数组变量,其成员是源文件名,在此文件名中定义了FUNCNAME数组变量中的相应外壳函数名称。 shell函数$ {FUNCNAME [$ i]}在文件$ {BASH_SOURCE [$ i]}中定义,并从$ {BASH_SOURCE [$ i + 1]}调用。
FUNCNAME
一个数组变量,包含当前在执行调用堆栈中的所有shell函数的名称。索引为0的元素是任何当前正在执行的Shell函数的名称。最底部的元素(具有最高索引的元素)是“ main”。该变量仅在执行Shell函数时存在。分配给FUNCNAME无效,并返回错误状态。如果未设置FUNCNAME,则即使随后将其重置,它也会失去其特殊属性。
该变量可以与BASH_LINENO和BASH_SOURCE一起使用。 FUNCNAME的每个元素在BASH_LINENO和BASH_SOURCE中都有相应的元素来描述调用堆栈。例如,从文件$ {BASH_SOURCE [$ i + 1]}在行号$ {BASH_LINENO [$ i]}处调用了$ {FUNCNAME [$ i]}。内置的调用方使用此信息显示当前的调用堆栈。
[来源:Bash手册]
评论
这个解决方案对我来说是有效的,而选定的答案只是间歇地起作用。我从来没有弄清楚为什么有时它会起作用,而不是其他人(也许我没有对采购外壳给予足够的关注)。
– Jim2B
2015年9月9日15:45
#4 楼
为了彻底和方便搜索者,这是它们的作用...这是一个社区Wiki,因此可以随时添加其他shell的等效项(显然,$ BASH_SOURCE将有所不同)。 />test.sh:
#! /bin/sh
called=$_
echo $called
echo $_
echo #! /bin/sh
source ./test.sh
echo $BASH_SOURCE
test2.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
$
Dash
$ ./test2.sh
./test.sh
./test.sh
./test.sh
$ zsh test.sh
echo
test.sh
$
Zsh
q4312078q
评论
我不明白:为什么叫= $ _;回声$ call;回声$ _?不会两次打印$ _吗?
– Ciro Santilli郝海东冠状病六四事件法轮功
2014-09-14 7:17
@CiroSantilli:并非总是如此,请阅读Bash手册中的$ _特殊参数:“在shell启动时,设置为用于调用在环境或参数列表中传递的正在执行的shell或shell脚本的绝对路径名。随后,扩展为扩展后,上一个命令的最后一个参数。还要设置为用于调用执行的每个命令的完整路径名,并放置在导出到该命令的环境中。检查邮件时,此参数保存邮件文件的名称。”
–亚当·罗森菲尔德
2014-09-17 19:14
问题在于源文件的标题为#! / bin / sh使其无法使用。这将启动/ bin / sh的新实例,设置变量,然后退出该实例,而使调用实例保持不变。
–JamesThomasMoon1979
19 Mar 6 '19 at 5:39
@ JamesThomasMoon1979:你在说什么? ashell脚本中以#开头的任何内容都是注释。 #! (shebang)仅在执行脚本的第一行时才具有特殊含义。作为源文件的第一行,它只是一个注释。
–斯科特
19年6月9日在4:17
#5 楼
在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=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
fi
echo $script
这些shell的输出:
q4312078q
我试图使其适用于csh / tcsh,但这太难了;我坚持使用POSIX。
#6 楼
我对社区Wiki的答案(来自Shawn J. Goff)有点困惑,所以我写了一个脚本来解决问题。关于$_
,我发现了这一点:_
作为传递给命令的环境变量的用法。这是一个环境变量,因此很容易错误地测试其值。下面是脚本,然后是输出。它们也在此要点中。
test-shell-default-variables.sh
#!/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:-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 q4312078q
```
`$shell ./printer.sh` (simple invocation) (q4312078q):
dash: ./printer.sh
bash: ./printer.sh
zsh : ./printer.sh
ksh : ./printer.sh
`$shell ./sourcer.sh` (via sourcing) (q4312078q):
dash: ./sourcer.sh
bash: ./sourcer.sh
zsh : ./printer.sh
ksh : ./sourcer.sh
`$shell ./linked.sh` (via symlink) (q4312078q):
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 :
------------------------------------------
}'`.
echolor() {
echo -e "\e[1;36m$@\e[0m"
}
tell_file() {
echo File \`""\` is:
echo \`\`\`
cat ""
echo \`\`\`
echo
}
SHELL_ARRAY=("$@")
test_command() {
for shell in "${SHELL_ARRAY[@]}"
do
prepare "$shell"
cmd="$(eval echo )"
# echo "cmd: $cmd"
printf '%-4s: ' "$shell"
{ env -i $cmd 2>&1 1>&3 | sed 's/^/[err]/'; } 3>&1
teardown
done
echo
}
prepare () {
shell=""
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=""
# 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 'q4312078q'
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
q4312078q
我们学到了什么?
$BASH_SOURCE
$BASH_SOURCE
只能在bash中使用。与
$BASH_PROFILE
唯一的区别是当前文件是由另一个文件提供的。在这种情况下,$BASH_SOURCE
包含源文件的名称,而不是源文件的名称。$_
在zsh中,
$_
在bash中具有与$_
相同的值。$_
$_
不受破折号和ksh的影响。在bash和zsh,
sh
衰减到最后一次调用的最后一个参数。bash将q4312079q初始化为“ bash”。
zsh使q4312079q保持不变。 “最后一个参数”规则)。
符号链接
通过符号链接调用脚本时,没有变量包含对目标位置的任何引用。链接,只有链接名称。
ksh
关于这些测试,ksh的行为就像破折号。
sh
通过名为q4312079q的符号链接调用bash或zsh时,对于这些测试,其行为类似于破折号。
#7 楼
要使脚本与bash和zsh兼容,而不是使用if语句,您只需编写${BASH_SOURCE[0]:-${(%):-%x}}
即可。如果定义了结果,则取自BASH_SOURCE[0]
;如果未定义BASH_SOURCE [0],则取自${(%):-%x}}
。#8 楼
对于bash shell,我发现@Dennis Williamson的答案最有帮助,但是在sudo
的情况下不起作用。这样做:if ( [[ $_ != q4312078q ]] && [[ $_ != $SHELL ]] ); then
echo "I'm being sourced!"
exit 1
fi
#9 楼
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
$> 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)
/tmp
来自source
cd /
$> source /tmp/source1.sh
$> 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)
(bash)
$BASH_SOURCE (/tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
来自不同相对路径的
/
source
和/tmp/a
关于
/var
在所有情况下,如果脚本添加了命令
echo '$> bash /tmp/source1.sh
(bash)
'"(q4312078q (/tmp/source1.sh)
$BASH_SOURCE (/tmp/source1.sh)
readlink -e $BASH_SOURCE (/tmp/source1.sh)
)"
然后
source
脚本始终打印q4312078q
但是,如果脚本运行,例如
q4312078q
,那么
/tmp/source1.sh
将是字符串值q4312079q。q4312078q
#10 楼
此答案描述了lsof
和一点grep魔术是如何似乎唯一有机会在tcsh下处理嵌套源文件的事情:/usr/sbin/lsof +p $$ | grep -oE /.\*source_me.tcsh
#11 楼
最棘手的部分是找到当前源文件是用于在Ubuntu中用作sh替换的破折号外壳。可以在源脚本中使用以下代码片段来确定其绝对路径。在bash中测试,zsh和dash分别作为dash和sh调用。NB:依赖于GNU coreutils程序包中的现代realpath(1)实用程序
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=q4312078q
;;
esac
echo $(realpath $result)
}
#12 楼
如果您需要包含脚本的目录的绝对路径,则可以使用以下代码段:BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]:-SCRIPT_PATH="${BASH_SOURCE[0]:-q4312078q}"
}" )" >/dev/null 2>&1 && pwd )"
如果只需要脚本的相对路径:
q4312078q
这些代码段应在不同的bash版本和zsh上工作。
#13 楼
wdir="$PWD"; [ "$PWD" = "/" ] && wdir=""
case "q4312079q" in
/*) scriptdir="${0%/*}";;
*) scriptdir="$wdir/${0#./}"; scriptdir="${scriptdir%/*}";;
esac
echo "$scriptdir"
这可能不适用于符号链接或源文件,但适用于普通文件。
作为参考。 @kenorb
没有目录名,读取链接,BASH_SOURCE。
评论
问题中的解释是,$ 0会为您提供有关当前正在运行的脚本的信息,而不是源脚本。
–斯科特
19年6月9日在4:10
#14 楼
实际上,“目录名$ 0”将为您提供脚本的路径,但您必须对其进行一些解释:$ cat bash0
#!/bin/bash
echo $0=q4312078q
dirname q4312078q
$ bash0 # "." appears in PATH right now.
q4312078q=./bash0
.
$ ./bash0
q4312078q=./bash0
.
$ $PWD/bash0
q4312078q=/home/00/bediger/src/ksh/bash0
/home/00/bediger/src/ksh
$ $PWD/../ksh/bash0
q4312078q=/home/00/bediger/src/ksh/../ksh/bash0
/home/00/bediger/src/ksh/../ksh
$ ../ksh/bash0
q4312078q=../ksh/bash0
../ksh
您必须准备处理“”。在某些常见情况下用作目录名称。我会做一些实验,因为我记得在“。”时ksh内置的目录名有所不同。出现在PATH中。
评论
这是源脚本,不是已执行的脚本。 $ 0仅包含用于交互式shell的“ bash”,这就是所有源脚本所看到的。
–卡斯卡贝尔
2010-12-08 16:32
评论
具有4200多个投票的相关问题:stackoverflow.com/q/59895/52074