强有力地在bash中传递部分命令

时间:2013-05-05 10:38:55

标签: arrays bash escaping syntax-error eval

我想在bash中传递部分命令,以便:

commandpart=( --flags "filename" >/dev/null )
command "${commandpart[@]}"

将评估为:

command --flags "filename" >/dev/null

以前这对我来说很有用,不幸的是将一个>放在一个bash数组中会导致语法错误。

  

意外令牌附近的语法错误`>'
  `commandpart =(--flags“filename”> / dev / null)'

我尝试过的其他事情都是把它全部插入一个字符串并eval

commandpart="--flags filename >/dev/null"
eval "command $commandpart"

但这会带来逃逸,空间等问题(并且eval不是最佳实践)

最好如何修复第一个示例中的语法错误而不转义<>&之类的字符?我想继续使用这个数组语法,因为它似乎比eval更强大,并且不需要转义。

如果没有,是否有另一种方法可以移动部分命令以满足我的需求?

奖励积分:如果我将参数传递给我的脚本,就像这样执行:

#!/bin/bash
echo "script running"
command "${@}"

我遇到了一个新问题,将>/dev/null添加到脚本调用会将其应用于脚本,而不是命令:

$ script >/dev/null

虽然转义它会将它应用于命令,但是作为没有预期效果的字符串。 (例如,如果命令是firefox,它将在名为'&gt; / dev / null'的页面上打开firefox并及时404)

2 个答案:

答案 0 :(得分:4)

来自bash(1):

  

一个简单的命令是一系列可选的变量赋值,后跟空格分隔的单词和重定向,并由控制操作符终止。第一个单词指定要执行的命令,并作为参数零传递。其余的单词作为参数传递给调用的命令。

这意味着重定向不是命令行的一部分。它们被bash解释为命令将运行的“环境”描述的一部分,与分配它之前的环境变量相同。

来自同一个bash(1):

  

扩展在分割为单词后在命令行上执行。

这暗示了这样一个事实:通过时间参数扩展(在你的情况下为“$ {commandpart [@]}”),单词已经与重定向分开了。由于这不太可能发生两次,这意味着参数扩展的结果不会被解释为重定向。

你可以通过创建一个引用不是重定向的数组元素的函数,按照bash引用规则,然后将它们作为参数传递给eval来完成这项工作。但是,该函数必须能够以与bash相同的方式区分重定向和“单词”,并且有many kinds。这也可能需要引用某些重定向的部分。

我建议不要存储/传递重定向,而是根据需要应用它们代替调用。如果您总是需要使用某些命令进行重定向,请创建包装函数或脚本。

答案 1 :(得分:2)

您需要阅读I'm trying to put a command in a variable, but the complex cases always fail!,了解这是一个问题,并且不会按照您希望的方式运行。