我正在定义一个用户应该执行的 shell 脚本source
。
是否有一种传统或智能的方式来提示用户这种情况,例如通过文件扩展名?
是否有我可以在文件本身中编写的shell代码,如果执行而不是获取它,这将导致它回显消息并退出,以便我可以帮助用户避免这种明显的错误?
答案1
假设您正在运行 bash,请将以下代码放在您想要获取但不执行的脚本的开头附近:
if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
echo "Hey, you should source this script, not execute it!"
exit 1
fi
在 bash 下,${BASH_SOURCE[0]}
将包含 shell 正在读取的当前文件的名称,无论该文件是正在获取还是正在执行。
相比之下,$0
是当前正在执行的文件的名称。
-ef
测试这两个文件是否是同一个文件。如果是,我们会提醒用户并退出。
POSIX也不-ef
是BASH_SOURCE
。虽然-ef
ksh、yash、zsh 和 Dash 支持,但BASH_SOURCE
需要 bash。 在zsh
但是,${BASH_SOURCE[0]}
可以替换为${(%):-%N}
.
答案2
不可执行的文件可以获取但不能执行,因此,作为第一道防线,不设置可执行标志应该是一个很好的提示......
编辑:我刚刚偶然发现的技巧:使 shebang 成为不是 shell 解释器的任何可执行文件,/bin/false
使脚本返回错误 (rc!=0)
#!/bin/false "This script should be sourced in a shell, not executed directly"
答案3
中建议了几种方法这个堆栈溢出帖子,其中,我喜欢基于函数的建议威拉万·普万托和斯普拉蒂克先生最好的:
正如 Wirawan Purwanto 建议的,最可靠的方法是检查
FUNCNAME[1]
在函数内:function mycheck() { declare -p FUNCNAME; } mycheck
然后:
$ bash sourcetest.sh declare -a FUNCNAME='([0]="mycheck" [1]="main")' $ . sourcetest.sh declare -a FUNCNAME='([0]="mycheck" [1]="source")'
这相当于检查 的输出
caller
、值main
并source
区分调用者的上下文。使用FUNCNAME[]
可以节省您捕获和解析caller
输出的时间。不过,您需要知道或计算您的本地呼叫深度才能正确。像脚本源自另一个函数或脚本之类的情况将导致数组(堆栈)更深。 (FUNCNAME
是一个特殊的 bash 数组变量,它应该具有与调用堆栈对应的连续索引,只要它不是 never 即可unset
。)
所以你可以在脚本的开头添加:
function check()
{
if [[ ${FUNCNAME[-1]} != "source" ]] # bash 4.2+, use ${FUNCNAME[@]: -1} for older
then
printf "Usage: source %s\n" "$0"
exit 1
fi
}
check
答案4
假设执行脚本只是无用而不是有害,您可以添加
return 0 || printf 'Must be sourced, not executed\n' >&2
到结尾脚本的。return
函数外部具有非零退出代码,除非正在获取文件。