【发布时间】:2015-04-23 10:42:37
【问题描述】:
我需要构造一个包含引用参数的复杂命令。碰巧的是,它们是 grep 的参数,所以我将使用它作为我的示例,并将命令深度简化到足以证明错误的程度。
让我们从一个工作示例开始:
> COMMAND='/usr/bin/grep _'
> echo $COMMAND
/usr/bin/grep _
> $COMMAND
foo <- I type this, and grep filters it out.
foo_ <- I type this, and.....
foo_ <- ... it matches, so grep emits it.
“foo”没有回显,因为它缺少下划线,“foo_”有一个,所以它被返回。让我们来演示一下这个问题:
> COMMAND='/usr/bin/grep "_ _"'
> echo -E $COMMAND
/usr/bin/grep "_ _"
> /usr/bin/grep "_ _" <- The exact same command line
foo <- fails to match
foo_ _ <- matches, so it gets echoed back
foo_ _
> $COMMAND <- But that command doesn't work from a variable
grep: _": No such file or directory
换句话说,当通过变量名调用此命令时,bash 将下划线之间的空格作为参数分隔符 - 尽管有引号。
通常,我会用反斜杠来解决这个问题:
> COMMAND='/usr/bin/grep "_\ _"'
> $COMMAND
grep: trailing backslash (\)
好的,也许我需要另一层转义反斜杠:
> COMMAND='/usr/bin/grep "_\\ _"'
12:32 (master) /Users/ronbarry> $COMMAND
grep: _": No such file or directory
现在我们回到第一点 - 命令行仍在空间中被分解。当然,我可以通过一些调试来验证所有这些,这可以确定反斜杠仍然存在,未转义,并且正在使用多个参数调用 grep:
> set -x
> $COMMAND
+ /usr/bin/grep '"_\\' '_"' <- grep is being called with two args
我有一个利用数组的问题的解决方案,但是对于大多数阅读过我的代码的人来说,以这种方式打包命令(在我的完整实现中,我将不打扰你)是不熟悉的。过度简化基于数组的命令的创建:
> declare -a COMMAND=('/usr/bin/grep' '-i' 'a b')
12:44 (master) /Users/ronbarry> ${COMMAND[*]}
foo <- Same old, same old
fooa B <- ...
fooa B <- Matches because of case-insensitive (-i) grep.
最后我们来回答这个问题。为什么 bash 在将字符串解释为命令时会分解字符串中的引用参数,为什么似乎没有一种字符串方式来使其工作?如果我将一个命令打包在一个字符串变量中,那么将该字符串的解释方式与字符串本身的解释方式不同,就违反了最小意外原则。如果有人可以向我指出一些涵盖所有这些的文档,并且会让我对为什么我必须诉诸于使用我的所有命令构建数组的无限丑陋机制感到平静,我将非常感激。
【问题讨论】:
标签: string bash variables command interpolation