【问题标题】:bash: get literal parameters passed to a script and execute them as a commandbash:获取传递给脚本的文字参数并将它们作为命令执行
【发布时间】:2013-08-20 10:46:11
【问题描述】:

目标和背景

我正在编写一个 bash 脚本(称为 foreach_repo),它应该将传递的参数作为 shell 命令执行,例如:

 foreach_repo hg status

应该执行命令hg status。 (它在存储库的复杂嵌套结构上执行此操作,我无法控制此结构,但我需要经常对它们进行批处理)。

这种类型的命令类似于sudo 和其他“高阶”命令;例如sudo hg status 将依次以超级用户权限执行hg status

在内部,我的脚本执行以下操作(给定标准输入上的存储库路径提要,由脚本的另一部分创建 - 与此问题无关):

while read repo do
    container="$repo/.."
    cd $base/$container
    $@
done

$@ 用于将传递的参数解释为要在存储库中执行的命令。

执行

这种方法适用于简单的命令,例如

foreach_repo hg status

将正确返回结构中每个存储库的状态列表。然而,更复杂的命令(带有转义符、引号......)被搞砸了。例如,当我尝试

foreach_repo hg commit -m "some message"

我明白了

abort: message: no such file or directory

因为引号被去掉了,所以实际执行的命令是:

hg commit -m some message

尝试的解决方案

手动转义引号或要传递的整个命令无效,使用$* 代替$@ 也无效。但是,像sudo 这样的命令可以处理这种情况,即:

sudo hg commit -m "some message"

会实际(并且正确地)执行

hg commit -m "some message"

我怎样才能完成同样的行为?

【问题讨论】:

    标签: bash shell mercurial


    【解决方案1】:

    你在正确的轨道上,并且几乎得到它。您只需要使用"$@" 而不是$@

    以下是 $*$@ 所做工作的摘要,包括引号和不带引号:

    • $*$@ 粘贴位置参数,然后将它们标记化(使用 $IFS)成单独的字符串。
    • "$*" 将位置参数粘贴为一个字符串,在每个字符串之间插入$IFS 的第一个字符(通常是空格)。
    • "$@" 粘贴位置参数,作为每个参数的字符串。

    例子:

    $ set foo bar "foo bar:baz"
    $ printf "%s\n" $*
    foo
    bar
    foo
    bar:baz
    $ printf "%s\n" $@
    foo
    bar
    foo
    bar:baz
    $ printf "%s\n" "$*"
    foo bar foo bar:baz
    $ printf "%s\n" "$@"
    foo
    bar
    foo bar:baz
    

    以下是设置$IFS 时发生的变化:

    $ IFS=:
    $ printf "%s\n" $*
    foo
    bar
    foo bar
    baz
    $ printf "%s\n" $@
    foo
    bar
    foo bar
    baz
    $ printf "%s\n" "$*"
    foo:bar:foo bar:baz
    $ printf "%s\n" "$@"
    foo
    bar
    foo bar:baz
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-23
      • 2011-06-06
      • 1970-01-01
      • 2022-12-08
      • 2013-08-03
      • 1970-01-01
      • 2014-10-25
      相关资源
      最近更新 更多