我有一个脚本,我不希望它调用退出,如果它是来源。
我想检查是否$0 == bash,但这有问题,如果脚本是从另一个脚本,或者如果用户从不同的shell,如ksh源。
是否有一种可靠的方法来检测脚本是否被引用?
我有一个脚本,我不希望它调用退出,如果它是来源。
我想检查是否$0 == bash,但这有问题,如果脚本是从另一个脚本,或者如果用户从不同的shell,如ksh源。
是否有一种可靠的方法来检测脚本是否被引用?
当前回答
编者注:这个答案的解决方案工作稳健,但只有bash。它可以简化为 (返回2 > / dev / null)。
博士TL;
尝试执行return语句。如果脚本没有来源,则会引发错误。您可以捕获该错误并按照需要进行操作。
把它放在一个文件中,并调用它,比如test.sh:
#!/usr/bin/env sh
# Try to execute a `return` statement,
# but do it in a sub-shell and catch the results.
# If this script isn't sourced, that will raise an error.
$(return >/dev/null 2>&1)
# What exit code did that give?
if [ "$?" -eq "0" ]
then
echo "This script is sourced."
else
echo "This script is not sourced."
fi
直接执行:
shell-prompt> sh test.sh
output: This script is not sourced.
来源:
shell-prompt> source test.sh
output: This script is sourced.
对我来说,这可以在zsh和bash中工作。
解释
如果您试图在函数之外执行return语句,或者如果脚本不是源代码,则return语句将引发错误。在shell提示符中尝试以下操作:
shell-prompt> return
output: ...can only `return` from a function or sourced script
你不需要看到错误消息,所以你可以将输出重定向到dev/null:
shell-prompt> return >/dev/null 2>&1
现在检查逃生码。0表示OK(没有发生错误),1表示发生错误:
shell-prompt> echo $?
output: 1
您还希望在子shell中执行return语句。当return语句运行它时…嗯……的回报。如果在子shell中执行它,它将从子shell返回,而不是从脚本返回。要在子shell中执行,请将其包装在$(…)中:
shell-prompt> $(return >/dev/null 2>$1)
现在,你可以看到子shell的退出代码,它应该是1,因为在子shell内部引发了一个错误:
shell-prompt> echo $?
output: 1
其他回答
我想对丹尼斯非常有用的回答提出一个小小的更正,让它更容易携带,我希望:
[ "$_" != "$0" ] && echo "Script is being sourced" || echo "Script is a subshell"
因为[[不被Debian POSIX兼容外壳识别(有些保留的IMHO), dash。同样,在shell中,可能需要使用引号来防止文件名中包含空格。
编者注:这个答案的解决方案工作稳健,但只有bash。它可以简化为 (返回2 > / dev / null)。
博士TL;
尝试执行return语句。如果脚本没有来源,则会引发错误。您可以捕获该错误并按照需要进行操作。
把它放在一个文件中,并调用它,比如test.sh:
#!/usr/bin/env sh
# Try to execute a `return` statement,
# but do it in a sub-shell and catch the results.
# If this script isn't sourced, that will raise an error.
$(return >/dev/null 2>&1)
# What exit code did that give?
if [ "$?" -eq "0" ]
then
echo "This script is sourced."
else
echo "This script is not sourced."
fi
直接执行:
shell-prompt> sh test.sh
output: This script is not sourced.
来源:
shell-prompt> source test.sh
output: This script is sourced.
对我来说,这可以在zsh和bash中工作。
解释
如果您试图在函数之外执行return语句,或者如果脚本不是源代码,则return语句将引发错误。在shell提示符中尝试以下操作:
shell-prompt> return
output: ...can only `return` from a function or sourced script
你不需要看到错误消息,所以你可以将输出重定向到dev/null:
shell-prompt> return >/dev/null 2>&1
现在检查逃生码。0表示OK(没有发生错误),1表示发生错误:
shell-prompt> echo $?
output: 1
您还希望在子shell中执行return语句。当return语句运行它时…嗯……的回报。如果在子shell中执行它,它将从子shell返回,而不是从脚本返回。要在子shell中执行,请将其包装在$(…)中:
shell-prompt> $(return >/dev/null 2>$1)
现在,你可以看到子shell的退出代码,它应该是1,因为在子shell内部引发了一个错误:
shell-prompt> echo $?
output: 1
这似乎在Bash和Korn之间是可移植的:
[[ $_ != $0 ]] && echo "Script is being sourced" || echo "Script is a subshell"
与此类似的行或赋值语句如pathname="$_"(带有稍后的测试和操作)必须位于脚本的第一行或shebang之后的行(如果使用了shebang,则应该用于ksh,以便它在大多数情况下工作)。
这并不完全是OP想要的,但我经常发现自己需要源代码脚本只是为了加载它的函数(即作为一个库)。例如,用于基准测试或测试目的。
下面是一个适用于所有shell(包括POSIX)的设计:
将所有顶级操作包装在run_main()函数中。 让您的源脚本检查不执行任何操作的初始-no-run参数;没有——no-run,它可以调用run_main。 使用以下方法获取脚本的源代码:
set -- --no-run "$@"
. script.sh
shift
问题是。或者来源是不可能将参数可移植地传递给脚本。POSIX shell忽略参数。并传递调用者的“$@”。
直截了当:您必须计算变量“$0”是否等于Shell的名称。
是这样的:
#!/bin/bash
echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
echo "The script was sourced."
else
echo "The script WAS NOT sourced."
fi
通过壳:
$ bash check_source.sh
First Parameter: check_source.sh
The script WAS NOT sourced.
通过来源:
$ source check_source.sh
First Parameter: bash
The script was sourced.
很难有一种100%可移植的方法来检测脚本是否来自源代码。
根据我的经验(使用Shellscripting 7年),唯一安全的方法(不依赖具有pid等的环境变量,这是不安全的,因为它是变量),你应该:
扩展你的“如果”的可能性 使用开关/箱子,如果你想。
这两个选项都不能自动缩放,但这是更安全的方式。
例如:
当您通过SSH会话源脚本时,变量“$0”(当使用source时)返回的值是-bash。
#!/bin/bash
echo "First Parameter: $0"
echo
if [[ "$0" == "bash" || "$0" == "-bash" ]] ; then
echo "The script was sourced."
else
echo "The script WAS NOT sourced."
fi
OR
#!/bin/bash
echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
echo "The script was sourced."
elif [[ "$0" == "-bash" ]] ; then
echo "The script was sourced via SSH session."
else
echo "The script WAS NOT sourced."
fi