I am running these two commands:
echo $(find ./ $OPT1 $OPT2 $OPT3)
echo find ./ $OPT1 $OPT2 $OPT3 | bash
and the weird thing is, the top command yields no results while the bottom one does. Why is that?
I am running these two commands:
echo $(find ./ $OPT1 $OPT2 $OPT3)
echo find ./ $OPT1 $OPT2 $OPT3 | bash
and the weird thing is, the top command yields no results while the bottom one does. Why is that?
The first runs find ./ $OPT1 $OPT2 $OPT3
word-splits and globs the output (no quotes around $()
), and passes it to echo
, which prints it. Which is mostly the same as just running the find
command, but newlines get turned to spaces, and if any file names printed by find
contain *
or ?
, they'll be expanded. Though if your IFS
contains something unusual, the word-splitting will be similarly unusual. (Also, $OPT1
and others are also not quoted, so they're split and globbed before passing to find
.)
The second prints find ./ $OPT1 $OPT2 $OPT3
, expanding the variables (again splitting and globbing, because no quotes), and passes the result to bash
, which runs it as a command. Again pretty much the same as just running the find
, but if the variables contain shell metacharacters, they'll be expanded (again) by the second shell.
The first one, note that the filename foo*
is expanded, globbing the all three:
$ touch foo1 foo2 foo\*
$ echo $(find .)
. ./foo2 ./foo* ./foo1 ./foo2 ./foo1
The second, note that the pipe to bash causes the inner variable to be expanded, like if you used eval
:
$ OPT='echo $BASH_VERSION'
$ echo $OPT
echo $BASH_VERSION
$ echo $OPT | bash
4.3.30(1)-release
$ eval $OPT # about the same
4.3.30(1)-release
Variable expansion is probably the simplest example of this, but it needs an exported variable or one that the other shell has in any case, like BASH_VERSION
here. (I can't come up with a sane example with find
for now.)
Depending on what your OPT
variables contain, the extra eval round might make the difference in if find
matches anything.