2

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?

  • are single quotes really necessary; single quotes prevents expansion of any meta-character including $ and \. – Ankit Apr 16 '13 at 12:49
  • @Ankit Yes, they are necessary. – 1.61803 Apr 16 '13 at 12:54
  • Can it be a multiple executions of command1 with each path? – piotrekkr Apr 16 '13 at 14:58
  • @piotrekkr No, command2 gives single-quoted POSIX paths separated by spaces. – 1.61803 Apr 16 '13 at 15:35
  • @1.61803 yeah but if I make them separate and use command1 'path 1' multiple times would be it ok? – piotrekkr Apr 16 '13 at 16:32
2

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

will give:

++ 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:

  1. '' becomes nothing.
  2. \' becomes a single quote (')
  3. 'bar' becomes bar

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).

  • eval "command1 $(command2)" it is. Thanks! – 1.61803 Apr 16 '13 at 17:22
1

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 getconf ARG_MAX.

0

Try something like this:-

path1="/etc/passwd"
path2="/var/log/secure"

[root@localhost base_filters]# ls -l "$path1" "$path2"
-rw-r--r--. 1 root root 1876 Mar 10 22:15 /etc/passwd
-rw-------. 1 root root 2408 Apr  5 23:09 /var/log/secure
0

Don't know if I fully understand your question but maby this will help:

$ var=$(echo "'/path/to/dir 1' '/path/to/dir 2' '/path/to/dir 3'")
$ echo -n $var | sed "s/^'\(.*\)'\$/\1/g" | sed "s/' '/\x00/g" | xargs -0 command1
0

Try playing around with IFS variable, so that space doesn't affect your script. I would store IFS in a variable and after completing actions of my script, i would restore the IFS.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.