If you need to pass the output from a command as an argument to another command, use command substitution. Similarly to what happens with variable substitutions, the result of command substitution undergoes word splitting (splitting into separate words at each character in
$IFS, whitespace by default) and wildcard expansion (globbing of file names). So , always use double quotes around command substitutions unless you want splitting and globbing to happen.
ls -- "$(./myscript)"
ls to stop processing options, this is necessary in case the file name printed by the script begins with
You have to print the literal file names. Don't add extra quoting from within the script.
There's actually one edge case where the argument is mangled: command substitution strips off any final newline from the command output. So whether the output is
foo↲bar↲↲↲ (I use
↲ to represent a newline character), the argument of the
ls command will be just
foo↲bar. This hardly ever happens in practice, because although newlines are allowed in file names, nobody uses them. Nonetheless it could be a security concern, because someone trying to attack your system might put newlines in a file name.
To handle final newlines, arrange for the command to output an extra non-newline character, and strip it off from the result of the command substitution.
output=$(./myscript; echo a)
ls -- "$output"
Passing multiple file names to a command
The one character that cannot appear in a file name or a command line argument is the null byte. The safe way of outputting multiple file names or other arguments to be passed to a command is to separate them with null bytes and call
xargs -0. This works on Linux, *BSD and OSX but is an extension to POSIX that other unix variants may lack. If the resulting command line is too long, xargs splits it and invokes the command multiple times.
… | xargs -0 ls
xargs expects an input format that no other common command produces. It is safe for use if the input contains no whitespace nor any of
A way to quote input for
xargs is to put a backslash before at least the following characters: newline, tab, space and
for x in …; do
printf '%s\n' "$x" | sed -e 's/[ '\''\"]/\\&/g' -e 's/$/\\$/' -e '$ s/\\$//'
done | xargs ls
Put a space and a tab instead of the two space characters inside brackets in the sed command.
Further notes on unprotected substitutions and quoting
In an unprotected variable or command susbtitution, for each word to which globbing happens, the four characters
\[*? are expanded. However, only the characters
[*? trigger globbing: a backslash without other globbing characters remains intact. Thus, if the current directory contains three files called
ls $(echo '?oo bar') calls
ls with the arguments
ls $(echo '?\oo b\ar') calls
ls with the arguments