命令行上的Bash表达式评估命令



背景:

我正在SGE的作业提交程序qSub中快速并行调用bash命令行表达式。在这样做的时候,我试图提交一个表达式(作为一个参数),以便在另一个脚本中运行,如下所示:

/runArguments.sh grep foo bar.txt>output.txt

runArguments.sh 看起来像这样:

#!/bin/bash  
${1} ${2} ${3} etc....to 12

这个想法是,我希望在脚本中评估"grep-foo-bar.txt>output.txt"。。。而不是在命令行上。在上面的示例中,"grep-foo-bar.txt"将在runArguments.sh执行期间进行评估,但输出重定向将在命令行上进行评估。我最终找到了一个使用"eval"的有效解决方案,如下所示,但我不明白为什么它有效。

问题

1) 为什么

./runArguments.sh eval "grep foo bar.txt > output.txt"

允许eval和表达式作为参数,但是

./runArguments.sh $(grep foo bar.txt > output.txt)

是否在调用脚本之前在命令行上求值?(将$(grep…)的输出作为参数)

2) 有更好的方法吗?

提前感谢!

你的第一个问题有点难回答,因为你自己已经回答了。正如您所看到的,命令替换($(...)`...`表示法)替换命令的输出,然后处理结果。例如:

cat $(echo tmp.sh)

转换为:

cat tmp.sh

所以在你的情况下,这个:

./runArguments.sh $(grep foo bar.txt > output.txt)

运行grep foo bar.txt > output.txt,获取其输出—这将毫无意义,因为您已将任何输出重定向到output.txt—并替换它,产生:

./runArguments.sh

(所以您的脚本运行时没有参数)。

相比之下,这个:

./runArguments.sh eval "grep foo bar.txt > output.txt"

不执行任何命令替换,因此脚本使用两个参数运行:evalgrep foo bar.txt > output.txt。脚本中的这个命令:

${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

因此相当于:

eval grep foo bar.txt '>' output.txt

它调用内置有五个参数的evalgrepfoobar.txt>output.txt。内置的eval将其参数组装成一个命令,并运行它们,甚至将>output.txt参数转换为输出重定向,因此上面的内容等效于:

grep foo bar.txt > output.txt

你已经知道这有什么作用了。:-)


至于您的第二个问题—不,没有比这更好的方法了。您需要将>作为参数传入,这意味着您需要使用eval ...bash -c "..."等,以便将其"转换"回有意义的输出重定向。如果你可以修改脚本,那么你可能想更改这一行:

${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

到此:

eval ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

这样就不需要在参数中处理这个问题。或者,实际上,你还不如把它改成这样:

eval ${@}

它将允许您传入十二个以上的参数;或者,更好的是,这个:

eval "${@}"

这将使您在分词和文件全局化等方面有更多的控制权。

最新更新