Brace expansion inside of command substitution - broken or is it me?
Hi all, I stumbled upon some rather strange behaviour that I just can't explain. Hopefully one of you can help me with that. :) Let's start with a simple brace expansion: $ echo {1..3} 1 2 3 Now add some quotes to prevent that expansion: $ echo "{1..3}" {1..3} Adding command substitution: $ echo $(echo "${1..3}") {1..3} So far, so good. It's what I expected. Let's add another level of quotes: $ echo "$(echo "{1..3}")" 1 2 3 Huh? Actually, I was expecting to get the same output as before. Some debug output: $ set -x $ echo "$(echo "{1..3}")" ++ echo 1 ++ echo 2 ++ echo 3 + echo 1 2 3 1 2 3 Why's that? a) As far as I understood, quotes inside of $(...) should not interfere with the outer quotes. b) Why are there three subshells? Actually, that {1..3} doesn't get expanded. It's more like the call above is effectively equivalent to this: $ echo "$(echo 1)" "$(echo 2)" "$(echo 3)" To sum up my question: Why do I get $ echo "$(echo "{1..3}")" 1 2 3 instead of $ echo "$(echo "{1..3}")" {1..3} ? I saw this happening on every version of Bash I could find -- ranging from Bash 4 in current Arch Linux to some old Bash 3 of msysgit[1] on Windows. Tried it on the last two or three versions of Ubuntu. And so on. To be honest, this almost convinces that I really missed something, so any help is very much appreciated. Below[2] is the information about my current system (Arch Linux) that "bashbug" gave me. Many thanks in advance, Peter [1] http://code.google.com/p/msysgit/ [2] bashbug-infos: Machine: i686 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -march=i686 -mtune=generic -O2 -pipe -DDEFAULT_PATH_VALUE='/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin' -DSTANDARD_UTILS_PATH='/usr/bin:/bin:/usr/sbin:/sbin' -DSYS_BASHRC='/etc/bash.bashrc' -DSYS_BASH_LOGOUT='/etc/bash.bash_logout' uname output: Linux pinguin 2.6.37-ARCH #1 SMP PREEMPT Fri Feb 11 16:55:18 UTC 2011 i686 AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ AuthenticAMD GNU/Linux Machine Type: i686-pc-linux-gnu Bash Version: 4.1 Patch Level: 9 Release Status: release
Re: Brace expansion inside of command substitution - broken or is it me?
Hi, On Fri, Feb 18, 2011 at 07:26:18PM -0500, Chet Ramey wrote: > Brace expansion is strictly textual, is performed before all other > expansions, and doesn't understand a whole lot of shell syntax. > It does understand a little about quoted strings, so what you get is > > echo "$(echo "1")" "$(echo "2")" "$(echo "3")" > > The preamble is "$(echo ", the portion to be expanded is {1..3}, and the > postscript is ")". thank you for clearing that up! Aha, I see. I've read that part about "strictly textual" and "performed before all other expansions" in the manual, but I didn't realize all the consequences. This means that my quotes get interpreted *after* the brace expansion is done, right? As a result, a call like echo "$(echo "{1..3}')' ends up as echo "$(echo "1')' "$(echo "2')' "$(echo "3')' and that surely won't work. This makes a lot more sense now. Thanks again, Peter