采购 bash 脚本时避免命令行参数传播

sun*_*mat 5 bash

我有一个 bash 脚本a.sh,如下所示:

#!/bin/bash
echo $#
echo $1
Run Code Online (Sandbox Code Playgroud)

和一个b.sh如下所示的脚本:

#!/bin/bash
source ./a.sh
Run Code Online (Sandbox Code Playgroud)

如果我调用,./a.sh我会正确地得到 0 和一个空行作为输出。调用时./a.sh blabla我得到 1 和 blabla 作为输出。

然而,当我打电话时,我也会得到 1 和 blabla 作为输出,即使没有从内部./b.sh blabla传递任何参数。a.shb.sh

这似乎与使用有关source(我必须使用它,因为在我的实际用例中,a.sh导出了一些变量)。如何避免参数被b.sh传播到a.sh?我考虑过使用eval $(a.sh),但这使我的echo陈述a.sh失败。我想在调用之前使用shift消耗参数,但我不一定知道有多少参数。b.sha.sh

Gor*_*son 11

问题的根源在于source命令工作方式的异常。在bash 手册页的“Shell 内置命令”部分中:

filename [ arguments ]
source filename [ arguments ]
[...] 如果提供任何参数,它们将在执行filename时成为位置参数。否则位置参数不变。

...这意味着您可以通过向 d 脚本提供不同的参数来覆盖主脚本的参数source,但您不能只是不向其传递参数。

幸运的是,有一个解决方法;只是source没有参数的上下文中的脚本:

#!/bin/bash
wrapperfunction() {
    source ./a.sh
}
wrapperfunction
Run Code Online (Sandbox Code Playgroud)

由于没有向 提供参数wrapperfunction,因此其中的 arg 列表为空。由于a.sh的命令是在该上下文中运行的,因此 arg 列表也为空。内部分配的变量在a.sh函数外部可用(除非它们被声明为local或类似的东西)。

(注意:我在 bash、zsh、dash 和 ksh93 中测试了这个,它在所有这些中都有效 - 好吧,除了 dash 没有该命令source,所以你必须使用.它。)

更新:我意识到您可以编写一个通用包装函数,该函数允许您指定文件名作为参数:

sourceWithoutArgs() {
    local fileToSource="$1"
    shift
    source "$fileToSource"
}
sourceWithoutArgs ./a.sh
Run Code Online (Sandbox Code Playgroud)

shift命令从函数的参数列表中删除文件名,因此当文件实际获取时它是空的。好吧,除非您向函数传递了额外的参数,在这种情况下,这些参数位于 arg 列表中并将被传递...所以您实际上可以使用此函数来替换 without-args 和 with-args 用法source

(这适用于 bash 和 zsh。如果您想在 ksh 中使用它,则必须删除local;要在 dash 中使用它,请替换source.