如何定义要获取但不运行的 shell 脚本

如何定义要获取但不运行的 shell 脚本

我正在定义一个用户应该执行的 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也不-efBASH_SOURCE。虽然-efksh、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、值 mainsource区分调用者的上下文。使用 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函数外部具有非零退出代码,除非正在获取文件。

相关内容