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

标签 bash shell mercurial

目标和背景

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

 foreach_repo hg status

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

这种类型的命令类似于 sudo 和其他“高阶”命令;例如 sudo hg status 将依次以 super 用户权限执行 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"

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

最佳答案

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

下面是 $*$@ 的作用总结,带引号和不带引号:

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

关于bash:获取传递给脚本的文字参数并将它们作为命令执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18333070/

相关文章:

linux - bash 脚本 : how to get item name on a radiolist using dialog

mysql - Mercurial 和MySQL

bash - 如何为 gcloud 获取 shell 命令完成(自动完成)?

bash - 根据 bash 中前后行处理一行

Python --command 命令行选项

mercurial - 如何修复 "AttributeError: ' 模块“对象没有属性 'set_binary'”?

mercurial - Mercurial中修订号后面的加号是什么

bash - 将星号转义为命令的一部分

linux - 历史 - 控制屏幕在原地滚动文本(向上箭头 -> 循环原地/相同位置的命令)

linux - 可以给出用于下载的当前目录大小列表的 shell 命令是什么?