You need to quote "$cmd"
- and maybe avoid the "
double-quotes. Anyway, to run this you do need to eval
it - and this is due to the |pipe
. A shell variable does not expand beyond the limits of a single simple command - and you're trying to run a compound command.
So:
cmd='grep -i "word1" filename | grep -i "word2"'
eval "$cmd"
Probably when you were expanding $cmd
without quotes you ran into filename generation and/or $IFS
issues. Just make sure it's reliably quoted and you'll be fine. Also verify that whatever is in "word[12]"
doesn't contain double-quotes or backslashes or whatever - else you'll need to reevaluate your quoting style there.
Looking closer now at your error and I can tell you exactly what it was:
grep: |: No such file or directory
grep: grep: No such file or directory
So if I do:
echo | echo
The first echo
prints a \n
ewline to the second echo
's stdin
. If I do:
set \| echo
echo "$@"
The first echo
prints each of its arguments, which are |
pipe and echo
respectively.
The difference is that the |
pipe in the first case is interpreted by the shell's parser to be a token and is interpreted as such. In the second case, at the same the shell is scanning for the |
pipe token it is also scanning for the $
expand token - and so the |
pipe is not yet there to be found because "$@"
has not yet been replaced with its value.
So if you do:
grep -i "word" filename \| grep -i "word2"
...you're likely to get the same results because the |
there does not delimit the commands, and is instead an argument to grep
in its infiles position.
Here's a look at how many fields you get when you split $cmd
with a default $IFS
:
printf '<%s> ' $cmd
<grep> <-i> <"word1"> <filename> <|> <grep> <-i> <"word2">
And here's what filename generation might do:
touch 'echo 1simple &&' 'echo 2simple'
eval echo*
cmd="grep \"foo bar\" file | grep \"match\""; eval $cmd
. In general you should useeval "$cmd"
but I have no idea how that can cause this error. Please runset -x
before executing the commands and add the output to your question.echo $0