在bash中从变量执行for循环中的命令

时间:2013-11-08 11:11:24

标签: bash shell variables loops eval

尝试在for循环中运行变量中定义的命令:

somevar="Bit of text"
cmd1="command \"search '$somevar' here\""
cmd2="command \"search '$somevar' there\""
for cmd in cmd1 cmd2 ; do
    eval \$$cmd
    ssh server1 eval \$$cmd
done

我已经考虑了我必须考虑的变体,例如循环内的ssh等,因为我的脚本需要这些变体。我认为eval是正确的方向,但是命令中的引号被解释的方式是错误的。

3 个答案:

答案 0 :(得分:5)

考虑这个破碎的例子:

$ cmd1="touch \"file with spaces\""
$ $cmd1

$cmd1展开之前处理报价,因此,这将创建三个名为"filewithspaces"的文件,而不是一个文件。在扩展后,可以使用eval $cmd强制删除引用。

即使它使用eval,行eval \$$cmd也有相同的引用问题,因为\$$cmd扩展为$cmd1,然后由eval进行评估与破碎的例子相同的行为。

eval的参数必须是实际命令,而不是表达式$cmd1。这可以使用变量间接来完成:eval "${!cmd}"

通过SSH运行时,不需要eval,因为远程shell也会执行引用删除。

所以这是固定循环:

for cmd in cmd1 cmd2 ; do
    eval "${!cmd}"
    ssh server1 "${!cmd}"
done

间接的替代方法是迭代cmd1cmd2的值而不是它们的名称:

for cmd in "$cmd1" "$cmd2" ; do
    eval "$cmd"
    ssh server1 "$cmd"
done

答案 1 :(得分:1)

我看到两个解决方案,要么将循环更改为:

for cmd in "$cmd1" "$cmd2" ; do
    ssh server1 $cmd
done

或者:

for cmd in cmd1 cmd2 ; do
    ssh server1 ${!cmd}
done

答案 2 :(得分:0)

而不是eval \$$cmd,您需要使用:

res=$(eval "$cmd")
ssh server1 "$res"