user331471
user331471

Reputation: 893

bash command substitution remove quotation

I did a little experiment with the bash and even after reading the relevant parts of the advanced bash scripting guide I can't explain what I'm observing.

Test situation: A directory named "test" with a subdirectory "target" and two files: "a b" and "c d" (the names contain blanks). I want to move the files into the target directory and I'm making it way more complicated then necessary:

cp $(echo "'a b' 'c d'") target

This gives me the following result:

cp: Aufruf von stat für „'a“ nicht möglich: Datei oder Verzeichnis nicht gefunden
cp: Aufruf von stat für „b'“ nicht möglich: Datei oder Verzeichnis nicht gefunden
cp: Aufruf von stat für „'c“ nicht möglich: Datei oder Verzeichnis nicht gefunden
cp: Aufruf von stat für „d'“ nicht möglich: Datei oder Verzeichnis nicht gefunden

It is as if something is removing the single quotation marks from the output of the inner echo command. But if I do a:

echo $(echo "'a b' 'c d'")

the result is:

'a b' 'c d'

Can some bash guru point me to the documentation that makes me understand that? This would make my friday complete!

Edit: I realized too late, that the 's are not removed but ignored. This is even more confusing to me and needs to be explained as well.

Upvotes: 1

Views: 631

Answers (2)

Tom Fenech
Tom Fenech

Reputation: 74595

The reason your approach isn't working:

cp $(echo "'a b' 'c d'") target

The command substitution (the bit between $( and )) is subject to word splitting. Your use of double quotes mean that echo sees only one argument. However, the parent shell splits the output of echo on white space into 'a b', 'c and d', i.e. four separate words.

As always, using set -x helps to visualise these things:

$ cp $(echo "'a b' 'c d'") target
++ echo ''\''a b'\'' '\''c d'\'''              # the subshell
+ cp ''\''a' 'b'\''' ''\''c' 'd'\''' target    # the parent shell

The single quotes show the boundaries of each word (although admittedly in this case, things are a little confused as you have your own single quotes in there too...).

If you were to put double quotes around the command substitution:

cp "$(echo "'a b' 'c d'")" target

then word splitting would not occur, meaning that the result of the command substitution would be a single word, although this would lead to a new problem:

$ cp "$(echo "'a b' 'c d'")" target
++ echo ''\''a b'\'' '\''c d'\'''
+ cp ''\''a b'\'' '\''c d'\''' target

Now cp is expecting to find a file named 'a b' 'c d', which you don't have either.

For the sake of completeness, the best way to copy these files is:

cp 'a b' 'c d' target

Upvotes: 6

Eugeniu Rosca
Eugeniu Rosca

Reputation: 5305

You need to do eval cp $(echo "'a b' 'c d'") target instead of cp $(echo "'a b' 'c d'") target

Upvotes: 1

Related Questions