Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
    
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

5 Answers 5

up vote 2 down vote accepted

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

share|improve this answer
    
eval "command1 $(command2)" it is. Thanks! –  1.61803 Apr 16 '13 at 17:22

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
share|improve this answer

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
share|improve this answer

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.

share|improve this answer

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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