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
#!/usr/bin/env bash
main() {
echo "Running main function."
# put your code here
echo -e "\nTOTAL TIME TO RUN main func:"
}
# Set the global variable `run` to "true" if the script is being executed and `main` should run, and
# set `run` to "false" otherwise--ex: if the script is being sourced in order to import functions
# from the script, but `main` should NOT run.
run_check() {
# DEMONSTRATE A FEW DIFFERENT TECHNIQUES
echo "Technique 1 (can be placed anywhere):"
echo " See: https://unix.stackexchange.com/a/424495/114401"
if [ "${BASH_SOURCE[0]}" -ef "$0" ]; then
echo " This script is being EXECUTED."
run="true"
else
echo " This script is being SOURCED."
fi
echo "Technique 2 [MY 2ND FAVORITE] (can be placed anywhere):"
echo " Modified from: https://stackoverflow.com/a/29967433/4561887"
if [ "${BASH_SOURCE[0]}" == "$0" ]; then
echo " This script is being EXECUTED."
run="true"
else
echo " This script is being SOURCED."
fi
echo "Technique 3 (requires another line which MUST be **outside** all functions):"
echo " Modified from: https://stackoverflow.com/a/28776166/4561887"
if [ "$script_is_being_executed" == "true" ]; then
echo " This script is being EXECUTED."
run="true"
else
echo " This script is being SOURCED."
fi
echo "Technique 4 [MY 1ST FAVORITE] (MUST be **inside** a function):"
echo " Modified from: https://stackoverflow.com/a/14706745/4561887"
echo " and https://unix.stackexchange.com/a/424552/114401"
if [ "${FUNCNAME[-1]}" == "main" ]; then
echo " This script is being EXECUTED."
run="true"
elif [ "${FUNCNAME[-1]}" == "source" ]; then
echo " This script is being SOURCED."
else
echo " ERROR: THIS TECHNIQUE IS BROKEN"
fi
}
# ==================================================================================================
# Main program entry point
# ==================================================================================================
# Only run main function if this file is being executed, NOT sourced.
# For Technique 3. This `return` statement MUST be called at a top-level scope, outside of all
# functions, in order to work! See their detailed explanation here for how it works:
# https://stackoverflow.com/a/28776166/4561887
(return 0 2>/dev/null) && script_is_being_executed="false" || script_is_being_executed="true"
run="false"
run_check
if [ "$run" == "true" ]; then
time main "$@"
fi
测试运行命令:
# 1. Execute the script in 2 ways:
# A. As an executable script
./bash/check_if_sourced_or_executed.sh
# B. By calling the bash interpreter
bash ./bash/check_if_sourced_or_executed.sh
# 2. Source the script in 2 ways:
# A. Bash source call
source ./bash/check_if_sourced_or_executed.sh
# B. (Recommended) POSIX-compliant source call
. ./bash/check_if_sourced_or_executed.sh
假设您正在运行 bash,请将以下代码放在您想要获取但不执行的脚本的开头附近:
在 bash 下,
${BASH_SOURCE[0]}
将包含 shell 正在读取的当前文件的名称,无论它是被获取还是被执行。相比之下,
$0
是当前正在执行的文件的名称。-ef
测试这两个文件是否是同一个文件。如果是,我们会提醒用户并退出。POSIX也不
-ef
是。BASH_SOURCE
虽然-ef
受 ksh、yash、zsh 和 Dash 支持,但BASH_SOURCE
需要 bash。 但是zsh
,${BASH_SOURCE[0]}
可以替换为${(%):-%N}
。一个不可执行的文件可以被获取但不能被执行,因此,作为第一道防线,不设置可执行标志应该是一个很好的提示......
编辑:我刚刚偶然发现的技巧:使shebang成为不是shell解释器的任何可执行文件,
/bin/false
使脚本返回错误(rc!= 0)这篇 Stack Overflow 帖子中建议了几种方法,其中我最喜欢Wirawan Purwanto和mr.spuratic建议的基于函数的方法:
因此,您可以添加到脚本的开头:
当您获取 shell 脚本时,shebang行将被忽略。通过放入无效的 shebang,您可以提醒用户该脚本被错误地执行:
错误消息将是这样的:
(任意)参数名称已经提供了强有力的提示,但错误消息仍然不是 100% 清楚。
source-this-script
我们可以使用放置在您的某处的实用程序脚本来解决此问题PATH
:现在,错误消息将是这样的:
与其他方法的比较
与其他答案相比,这种方法只需要对每个脚本进行最少的更改(并且有一个 shebang 行有助于在编辑器中检测文件类型并指定 shell 脚本方言,因此甚至有好处)。缺点是有点不清楚的错误消息,或者(一次性)添加了另一个 shell 脚本。
但是,它不会阻止通过 显式调用
bash path/to/script.sh
(感谢@muru!)。假设执行脚本只是无用而不是有害,您可以添加
到脚本的结尾。
return
除非正在获取文件,否则函数外部具有非零退出代码。这是我编制的 4 种技术。如果脚本正在执行而不是sourced ,您可以以编程方式决定要做什么。
来自我的 eRCaGuy_hello_world 存储库中的check_if_sourced_or_executed.sh:
测试运行命令:
另请参阅我在此处描述 Stack Overflow 上的 4 种技术:https ://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced/70662049#70662049