我正在尝试执行存储在变量中的命令:
cmd="grep -i \"word1\" filename | grep -i \"word2\""
eval $cmd
但是当我执行脚本时,我收到错误:
grep: |: No such file or directory
grep: grep: No such file or directory
如何执行像我的示例中那样的命令而不出现此错误?
答案1
您需要引用"$cmd"
- 并且可能避免使用"
双引号。不管怎样,要运行它,你确实需要eval
它 - 这是由于|pipe
. shell 变量不会扩展到超出单个简单命令的限制 - 并且您正在尝试运行复合命令。
所以:
cmd='grep -i "word1" filename | grep -i "word2"'
eval "$cmd"
可能当您在没有引号的情况下进行扩展时,$cmd
您会遇到文件名生成和/或$IFS
问题。只要确保它被可靠地引用就可以了。还要验证其中的内容"word[12]"
不包含双引号或反斜杠或其他任何内容 - 否则您需要在那里重新评估您的引用样式。
现在仔细看看你的错误,我可以准确地告诉你它是什么:
grep: |: No such file or directory
grep: grep: No such file or directory
所以如果我这样做:
echo | echo
第一个将 ewlineecho
打印\n
到第二echo
个stdin
。如果我做:
set \| echo
echo "$@"
第一个echo
打印它的每个参数,分别是|
管道和echo
。
不同之处在于,|
第一种情况下的管道被 shell 的解析器解释为标记,并被如此解释。在第二种情况下,shell 在扫描|
管道令牌的同时,也在扫描$
扩展令牌 - 因此|
管道尚未被发现,因为"$@"
尚未被其值替换。
所以如果你这样做:
grep -i "word" filename \| grep -i "word2"
...您可能会得到相同的结果,因为 There|
没有分隔命令,而是grep
它的参数内文件位置。
$cmd
以下是使用默认值进行拆分时获得的字段数量$IFS
:
printf '<%s> ' $cmd
<grep> <-i> <"word1"> <filename> <|> <grep> <-i> <"word2">
文件名生成可能会执行以下操作:
touch 'echo 1simple &&' 'echo 2simple'
eval echo*
答案2
对于我来说使用方法错误多变的保存并执行任何命令。还有更好的选择——功能:
my_cmd() {grep -i "word1" filename | grep -i "word2"}
就这些。
或者您可以使用不同的参数,例如:
my_cmd() {grep -i "$1" "$3" | grep -i "$2"}
然后通过调用它
my_cmd word1 word2 filename
答案3
对于您发布的示例,您不需要评估。只需像这样执行变量:
cmd="grep -i \"word1\" filename | grep -i \"word2\""; # added missing " at the end
$cmd
注意你的报价。也许这样的事情不太容易出错:
cmd='grep -i "word1" filename | grep -i "word2"';