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

kmo*_*man 3 bash shell mercurial

目标和背景

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

 foreach_repo hg status
Run Code Online (Sandbox Code Playgroud)

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

这种类型的命令sudo与其他"高阶"命令类似; 例如sudo hg status,反过来会hg status以超级用户权限执行.

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

while read repo do
    container="$repo/.."
    cd $base/$container
    $@
done
Run Code Online (Sandbox Code Playgroud)

其中$@的意思是将传递的参数解释为要在存储库中执行的命令.

执行

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

foreach_repo hg status
Run Code Online (Sandbox Code Playgroud)

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

foreach_repo hg commit -m "some message"
Run Code Online (Sandbox Code Playgroud)

我明白了

abort: message: no such file or directory
Run Code Online (Sandbox Code Playgroud)

因为引号被剥离,所执行的实际命令是:

hg commit -m some message
Run Code Online (Sandbox Code Playgroud)

试图解决方案

手动转义引号或要传递的整个命令都没有效果,也没有使用$*而不是$@.但是,像这样的命令sudo可以处理这种情况,即:

sudo hg commit -m "some message"
Run Code Online (Sandbox Code Playgroud)

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

hg commit -m "some message"
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*ung 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
Run Code Online (Sandbox Code Playgroud)

以下是您设置时的更改$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
Run Code Online (Sandbox Code Playgroud)