【问题标题】:Avoid command line arguments propagation when sourcing bash script采购 bash 脚本时避免命令行参数传播
【发布时间】:2020-04-08 14:22:59
【问题描述】:

我有一个 bash 脚本 a.sh,看起来像这样:

#!/bin/bash
echo $#
echo $1

还有一个脚本b.sh,看起来像这样:

#!/bin/bash
source ./a.sh

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

但是,当我调用 ./b.sh blabla 时,我也会得到 1 和 blabla 作为输出,即使在 b.sh 内没有将任何参数传递给 a.sh

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

【问题讨论】:

  • 这不是从b 传播到a 的参数。这是从ba 的代码。这就是source存在的原因。否则,在子 shell 中的标准执行就足够了。
  • 那么不要使用source#!/bin/bash ./a.sh
  • 你可以在采购之前转移:for arg in "$@"; do shift; done
  • 我这样做的原因source 是我需要在a.sh 中导出的变量,以便以后在b.sh 中可用。
  • 所以你基本上是想让a.sh改变b.sh的环境,同时也阻止a.sh访问b.sh的环境。这怎么可能?

标签: bash


【解决方案1】:

问题的根源在于source 命令的工作方式异常。来自bash man page,在“Shell 内置命令”部分:

文件名 [参数]
来源 文件名 [参数]
[...] 如果提供了任何 arguments,它们将成为执行 filename 时的位置参数。否则位置参数不变。

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

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

#!/bin/bash
wrapperfunction() {
    source ./a.sh
}
wrapperfunction

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

(注意:我在 bash、zsh、dash 和 ksh93 中对此进行了测试,并且它适用于所有这些 - 好吧,除了 dash 没有 source 命令,所以你必须使用 @987654331 @ 代替。)

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

sourceWithoutArgs() {
    local fileToSource="$1"
    shift
    source "$fileToSource"
}
sourceWithoutArgs ./a.sh

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

(这在 bash 和 zsh 中有效。如果你想在 ksh 中使用它,你必须删除 local;如果要在 dash 中使用它,请将 source 替换为 .

【讨论】:

    猜你喜欢
    • 2017-08-19
    • 2014-06-28
    • 1970-01-01
    • 2018-02-17
    • 1970-01-01
    • 2011-10-16
    • 2017-10-07
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多