5

For example, I want to put some file names inside braces for expansion like this:

$ ls
blue_texture  blue_waves  green_light
$ ls -m | tr -d ' \n'
blue_texture,blue_waves,green_light 
$ echo foo/bar/{`ls -m | tr -d ' \n'`}
foo/bar/{blue_texture,blue_waves,green_light}

My question why doesn't brace expansion work here? I expected it to work as following:

$ echo foo/bar/{blue_texture,blue_waves,green_light}
foo/bar/blue_texture foo/bar/blue_waves foo/bar/green_light

2 Answers 2

7

The reason this does not work is because bash performs brace expansion before command substitution (the Bash Reference Manual has some information about this). The substitution is not performed until after the brace expansion already occurred.

The only way you could do this is by using eval, but do not do that in this case, as you will allow arbitrary command execution.

Instead you have to seek some other method. This should produce the output you seek:

for file in *; do
    printf '%s ' "foo/bar/$file"
done; echo
0
2

With zsh:

files=(*)
echo foo/bar/$^l

(${^array} turns on brace-expansion style expansion for the array).

Or:

echo ./*(:s:.:foo/bar:)

Applies a history-expansion style substitution to filename expansion.

With any shell

printf 'foo/bar/%s\n' *

Or:

set -- *
for i do
  set -- "$@" "foo/bar/$i"
  shift
done
echo "$@"

(note that echo in most shells performs some transformations on the arguments it gets so is better avoided for arbitrary input).

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .