Very simplified, bash will:
- Parse a command or structure, then for each command:
- Apply brace expansion
- Apply parameter expansion
- Do word splitting
- Apply pathname expansion
- Execute the result
Handling of ||
happens during parsing in step 1, but you expand it in step 3. As a result, it's treated as a regular string as if running test -e a.txt "||" test -e b.txt
.
It will similarly fail for commands like echo {1..10}
which would require re-doing #2, and echo $PATH
which would require re-doing #3.
Meanwhile, it will work for echo Hello
(#4) and ls *.png
(#4/#5) because these only use features that come after.
While having a command in a string is a code smell indicating that you're painting yourself into an awkward corner, you can use eval
to apply all the steps over from #1 on a string of your choice:
cmd="test -e a.txt || test -e b.txt"
eval "$cmd"