如何检测脚本是否正在被引用

337

我有一个脚本,如果它被源引用,我不想让它调用exit

我考虑检查$0 == bash,但是如果脚本从另一个脚本中被源引用,或者用户从不同的shell(如ksh)中源引用它,则存在问题。

有没有一种可靠的方法来检测脚本是否正在被源引用?


4
我曾经遇到过类似的问题,解决方法是在任何情况下都避免使用“exit”命令;无论哪种情况,“kill -INT $$”命令都可以安全地终止脚本。 - JESii
4
你有注意到这个答案吗?它是在被接受的答案5年后给出的,但它具有“电池内置”的特点。 - raratiru
25个回答

0

我需要一个适用于 [mac, linux] 并且 bash 版本 >= 3 的一行代码,但是这些答案都不符合要求。

[[ ${BASH_SOURCE[0]} = $0 ]] && main "$@"

0

另一种解决方案(依赖于GNU coreutils中的readlink):

if [ "$(readlink -f "$(command -v "$0")")" != "$(readlink -f /proc/$$/exe)" ]; then
  echo "Is executed"
fi

这个比较:

  1. 当前命令的名称(如果是执行:脚本名称,如果是源代码:shell 解释器)
  2. 当前可执行文件(始终为 shell 解释器)

0

这是从其他答案中分离出来的,与“通用”的跨shell支持有关。尽管略有不同,但这与https://dev59.com/GXE85IYBdhLWcg3wpFEa#2942183非常相似。其弱点在于客户端脚本必须尊重如何使用它(即首先导出一个变量)。优点是这很简单,应该可以在“任何地方”工作。以下是您可以剪切和粘贴的模板:

# NOTE: This script may be used as a standalone executable, or callable library.
# To source this script, add the following *prior* to including it:
# export ENTRY_POINT="$0"

main()
{
    echo "Running in direct executable context!"
}

if [ -z "${ENTRY_POINT}" ]; then main "$@"; fi

注意:我使用export只是为了确保这种机制可以扩展到子进程中。


0

直截了当地说:您必须评估变量"$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


通过 SHELL:

$ bash check_source.sh 
First Parameter: check_source.sh

The script WAS NOT sourced.

通过 SOURCE:

$ source check_source.sh
First Parameter: bash

The script was sourced.



检测脚本是否被引用的100%可移植方式相当困难。

根据我的经验(使用Shell脚本7年),唯一安全的方法(不依赖于具有PIDs等环境变量,这是不安全的因为它是VARIABLE)是:

  • 扩展if语句的可能性
  • 如果需要,可以使用switch/case。

这两个选项都无法自动扩展,但这是更安全的方式。



例如:
当您通过SSH会话源代码时,使用source命令返回的变量"$0"的值为-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

或者

#!/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

2
因为这是明显错误的,所以被踩了:/bin/bash -c '. ./check_source.sh'会显示The script WAS NOT sourced.。同样的错误:ln -s /bin/bash pumuckl; ./pumuckl -c '. ./check_source.sh' -> The script WAS NOT sourced. - Tino
2
你的点踩改变了整个情景并做出了巨大的贡献,Tino。谢谢! - ivanleoncz

-1

使用shebang行并检查它是否正在执行。

您的脚本应该有一个shebang行#!/path/to/shell,指定它应该在哪个shell中运行。否则,您还将遇到其他跨shell兼容性问题。

因此,您只需要检查它是否正在执行,尝试一个在被源化时不起作用的命令即可。

例如,对于Bash脚本:

#!/usr/bin/env bash

if (return 0 2>/dev/null); then
    echo "Script was sourced."
fi

这种方法对 zsh 和 sh 也适用,只需更改 shebang 行即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接