How can I make command substitution pass a list of single-quoted POSIX paths separated by spaces?
command1 $(command2) command1 '/path/to/file 1' '/path/to/file 2' '/path/to/file 3'
How can I trace the expansion?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
You can see exactly what command is being run by using
set -x. A rather silly example:
$ echo $(echo "foo 'bar baz' taz\\ jaz") foo 'bar baz' taz\ jaz
++ echo 'foo '\''bar baz'\'' taz\ jaz' + echo foo ''\''bar' 'baz'\''' 'taz\' jaz foo 'bar baz' taz\ jaz
This is somewhat hard to read, because of all the escaping. For example, that second word:
\'becomes a single quote (
so that parameter is passed as
'bar. You can confirm with something like this (assuming you have Data::Dump installed, which isn't the default, unfortunately) Note the
$(echo… has been copied verbatim to the perl line:
$ perl -MData::Dump=pp -E 'pp @ARGV' $(echo "foo 'bar baz' taz\\ jaz") ("foo", "'bar", "baz'", "taz\\", "jaz")
What's happening here is that bash is doing word splitting (based off
$IFS), not argument parsing. So you, unfortunately, probably have to use
eval, and deal with all the risk that entails.
$ eval "echo $(echo "foo 'bar baz' taz\\ jaz")" foo bar baz taz jaz
(Also, I'll note, if you can get your command to generate its output as a list of names, separated by NUL, that would be easy to deal with using
xargs -0 and further, fully safe).
You are in the rare position to have a list of files that is in a format that
xargs understands. So run
command1 | xargs command2
Note that on some unix variants, if the output of
command1 is huge, it will be impossible to run
command2 with all the file names due to the command line length limit. The downside of using
xargs is that it will run the command several times instead of properly reporting an error. You can check the command line length limit with