我有 2 个 shell 脚本,file1.sh 和 file2.sh
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
echo "Hello"
文件2.sh
#!/usr/bin/env bash
source file1.sh
echo $var1
echo $var2
当我执行 file2.sh 时,我得到以下输出
Hello
/data/share
password
但我的预期输出是
/data/share
password
file1.sh 在 file2.sh 中引用时被执行。如何在不执行 file1.sh 的情况下在 file2.sh 中单独导入变量?
答案1
当我有一个 bash 脚本时,我希望它在被调用时和被执行时的行为有所不同(或者换句话说,脚本中有我想访问的数据项,但当时不想执行任何代码),我使用三种选项。评论在一定程度上涉及了它们。
选项一
确定何时采购并在适当的时候结束“采购”
将脚本分成两个部分,在到达第二个较低部分之前,从脚本中退出
创建具有定义(函数/变量分配/等)的脚本的上部,但不直接执行代码。
在可执行代码部分开始之前,放置一个逻辑,如果检测到脚本正在被调用,它将退出脚本。以下代码段将执行此操作:
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
# --- End Definitions Section ---
# check if we are being sourced by another script or shell
[[ "${#BASH_SOURCE[@]}" -gt "1" ]] && { return 0; }
# --- Begin Code Execution Section ---
echo "Hello"
echo $var1
echo $var2
文件2.sh
#!/usr/bin/env bash
source file1.sh
echo "$var1"
echo "$var2"
运行 ./file2.sh 的输出
$ ./file2.sh
/data/share
password
选项二
这个通常只用于复杂情况,而对于这个特定示例来说,它有点矫枉过正。我在要获取源代码的文件中创建一个函数,并在该函数中确定应该对调用者提供什么。在本例中是两个导出的变量。通常,当我有关联数组时,我会使用这种模式,否则几乎不可能处理这些数组。此外,调用者应该删除 tmp 文件;但在本例中我没有这样做:
文件1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
exportCfg() {
tmpF=$(mktemp)
declare -p var1 var2 > "$tmpF"
echo "$tmpF"
}
if [ "$1" == "export" ]; then
exportCfg;
exit 0;
fi
echo "Hello"
echo $var1
echo $var2
文件2.sh
#!/usr/bin/env bash
source $(./file1.sh export)
echo "$var1"
echo "$var2"
执行file2.sh的输出与上面相同
选项 3
我处理这个问题的最后一个常用方法是使用一个只包含定义的库文件,并且没有在源代码或直接运行时执行的代码。这只是一个划分代码的问题。我有一组包含常用函数的 bash“库”,并且通常在每个项目的基础上设置一个小型可源代码库来存储配置数据(常量)。如果该数据包括填充的数组,那么我还将使用选项 2 的版本。
答案2
如果你的变量都以相同的方式导出(导出 foo=bar),然后你可以轻松地使用狂欢流程替代功能:
source <(grep '^export .*=' file1.sh)
手册页摘录:
进程替换 在支持命名管道 (FIFO) 或 /dev/fd 方法命名打开文件的系统上支持进程替换。它采用 <(list) 或 >(list) 的形式。进程列表运行时,其输入或输出连接到 FIFO 或 /dev/fd 中的某个文件。此文件的名称作为扩展的结果作为参数传递给当前命令。如果使用 >(list) 形式,则写入文件将为列表提供输入。如果使用 <(list) 形式,则应读取作为参数传递的文件以获取列表的输出。