I found an unexpected behavior in a bash script recently and I'd like to understand it before I work around it. Here's a simplified example:
#! /bin/sh
SCRIPT="/tmp/echoscript.sh >> /tmp/log"
/bin/sh ${SCRIPT}
echoscript.sh just does 'echo "abc"'
The unexpected thing is that 'abc' goes to the terminal and not to the /tmp/log file. Why is that?
If I change the third line to:
/bin/sh ${SCRIPT} >> /tmp/log
Then I get the expected result; 'abc' goes to the log file.
You can't put redirections in variables like that. When you do Bash interprets /bin/sh ${SCRIPT}
as if you wrote:
/bin/sh "/tmp/echoscript.sh" ">>" "/tmp/log"
Notice how ">>"
is quoted, killing the attempted redirection. This happens because Bash parses a command in phases, and parsing redirections happens before variable expansion. Variable values are not checked for redirections.
When variables are expanded, the only further processing on the result is word splitting and wildcard expansion (aka globbing). The result is not scanned for other special operators, like redirection.
If you want full reprocessing of the command line, you have to use eval
:
eval "/bin/sh ${SCRIPT}"
This won't do what you expect since the redirect isn't being processed in ${SCRIPT}. You'll get /bin/sh: /tmp/echoscript.sh >> /tmp/log: No such file or directory
.
You'll need to tell the shell to evaluate ${SCRIPT} before running it, like this:
eval /bin/sh ${SCRIPT}
$ cat /tmp/log
abc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With