bash:获取传递给脚本的文字参数并将其作为命令执行

时间:2013-08-20 10:46:12

标签: bash shell mercurial

目标和背景

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

 foreach_repo hg status

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

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

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

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"

如何实现相同的行为?

1 个答案:

答案 0 :(得分:7)

你走在正确的轨道上,几乎得到了它。您只需使用"$@"代替$@

以下是$*$@执行操作的摘要,包括和不包含引号:

  • $*$@粘贴位置参数,然后将它们(使用$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