通过bash中的变量将标志传递给命令

时间:2012-03-03 15:42:37

标签: bash

我有一个复杂的脚本,它从文件中获取变量并使用它们来运行程序(特别是Wine)

从另一个文件中的变量传递选项无法按预期工作:

#!/bin/bash
. settingsfile
wine $run

在另一个文件中:

run="run.exe -withoption \"This text\""

当我将wine $run更改为echo wine $run时,它会回显一个字符串,当明确运行时,它会正常工作:

#!/bin/bash
. settingsfile
wine run.exe -withoption "This text"

修改:使用#!/bin/bash -x进行操作会向我显示:

+ wine run.exe -withoption '"This' 'text"'

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:8)

问题在于"Thistext"被视为单独的参数,每个参数都包含双引号,而不是单个参数This text。如果你编写一个函数来打印每行一个参数,你可以看到这个;这样:

function echo_on_separate_lines ()
{
  local arg
  for arg in "$@" ; do
    echo "<< $arg >>"
  done
}
run="run.exe -withoption \"This text\""
echo_on_separate_lines $run

打印出来:

<< run.exe >>
<< -withoption >>
<< "This >>
<< text" >>

而不是:

<< run.exe >>
<< -withoption >>
<< This text >>

最简单的解决方案是使用eval来重新处理引用:

run="run.exe -withoption \"This text\""
wine $run     # or better yet:   wine "$run"

但更强大的解决方案是让run成为数组,然后您可以将其称为"${run[@]}"

run=(run.exe -withoption "This text")
wine "${run[@]}"

以便从一开始就正确处理报价。

答案 1 :(得分:5)

简短回答:见BashFAQ #050: I'm trying to put a command in a variable, but the complex cases always fail!

答案很长:将引号放在变量中没有任何用处,因为bash在用它们的值替换变量之前解析引号;这意味着当它被$run替换为run.exe -withoption "This text"时,它已经完成引用解析,并且不会再回过头来注意那些双引号,这意味着它们不要做你期望的事。

BTW,使用echo来检查发生的事情是非常误导的,因为echo会在解析后显示的参数,但是你正在阅读就好像它在解析之前显示它们一样。相反,使用@ Eduardo关于-x的建议来了解真正发生的事情。 (顺便说一句,您也可以使用set -x为脚本中有趣的部分启用该功能,然后set +x将其关闭。)

那你怎么解决呢?通常,最好的方法是将命令放在数组而不是简单变量中,然后使用惯用语"${arrayname[@]}"将每个数组元素作为单独的参数传递:

run=(run.exe -withoption "This text")
wine "${run[@]}"