让我们看一个例子:在我的main.sh中,我想要获取a.sh和b.sh的源代码。然而,A.sh可能已经收购了b.sh。因此,它将导致b.sh中的代码执行两次。c++中是否有类似"include guard"的机制?
如果您正在使用脚本,您通常使用它们来定义函数和/或变量。
这意味着您可以通过测试脚本定义的函数或变量(其中之一)来测试脚本是否已经被引用过。
例如(in b.sh
):
if [ -z "$B_SH_INCLUDED" ]
then
B_SH_INCLUDED=yes
...rest of original contents of b.sh
fi
据我所知,没有别的方法可以做这件事。特别是,不能提前退出或返回,因为这会影响到生成文件的shell。您不必使用仅用于文件的名称;您可以使用文件始终定义的名称。
在bash中,早期返回不影响源文件,它返回源文件,就好像当前文件是一个函数一样。我更喜欢这种方法,因为它避免了在if...fi
中包装整个内容。
if [ -n "$_for_example" ]; then return; fi
_for_example=`date`
br:
Bash有一个源保护机制,可以让你决定在执行或源时做什么。
长版:
在使用Bash源代码的这些年里,我发现有一种不同的方法工作得很好,我将在下面讨论。
我遇到的问题与最初的海报类似:
- 查找其他脚本导致双脚本执行
- 此外,脚本在像BATS 这样的单元测试框架下的可测试性较差
我的解决方案的主要思想是以一种可以安全地多次获取的方式编写脚本。一个主要的部分是功能的提取(与一个大的脚本相比,它不会呈现非常可测试的)。
因此,只定义了函数和全局变量,其他脚本可以随意引用。
例如,考虑以下三个bash脚本:main.sh
#!/bin/env bash
source script2.sh
source script3.sh
GLOBAL_VAR=value
function_1() {
echo "do something"
function_2 "completely different"
}
run_main() {
echo "starting..."
function_1
}
# Enter: the source guard
# make the script only run when executed, not when sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
run_main "$@"
fi
script2.sh
#!/bin/env bash
source script3.sh
ALSO_A_GLOBAL_VAR=value2
function_2() {
echo "do something ${1}"
}
# this file can be sourced or be executed if called directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
function_2 "$@"
fi
script3.sh
#!/bin/env bash
export SUPER_USEFUL_VAR=/tmp/path
function_3() {
echo "hello again"
}
# no source guard here: this script defines only the variable and function if called but does not executes them because no code inside refers to the function.
注意script3.sh
的来源是两次。但是,由于只定义了函数和变量,因此在编译过程中不会执行函数代码。
执行从运行main.sh
开始,正如您所期望的那样。
当涉及到依赖循环时,可能有一个缺点(通常是一个坏主意):我不知道如果文件(直接或间接)相互依赖,Bash会如何反应。
我个人通常使用
set +o nounset # same as set -u
在我的大多数脚本中,因此我总是把它关闭,然后再打开。
#!/usr/bin/env bash
set +u
if [ -n "$PRINTF_SCRIPT_USAGE_SH" ] ; then
set -u
return
else
set -u
readonly PRINTF_SCRIPT_USAGE_SH=1
fi
如果你不喜欢nounset,你可以这样做
[[ -n "$PRINTF_SCRIPT_USAGE_SH" ]] && return || readonly PRINTF_SCRIPT_USAGE_SH=1