Bash is weird.

Consider the following command:
echo <(cat /etc/{motd,passwd})

(you can replace "echo" with any command that takes one file as argument and cannot take it as stdin)

It's obvious that the goal is to expand this to:
echo <(cat /etc/motd /etc/passwd)

Then to:
echo /dev/fd/63

However, it doesn't work like this:
$ echo <(cat /etc/{motd,passwd}) ++ cat /etc/motd ++ cat /etc/passwd + echo /dev/fd/63 /dev/fd/62 /dev/fd/63 /dev/fd/62

But bash doesn't work like this. Brace expansion is done first, but inside parameters of the command (that is, <(cat /etc/{motd,passwd})) not words. So when <(cat /etc/{motd,passwd}) is expanded, the prefix is <(cat /etc/, the suffix is ")", so it's expanded to <(cat /etc/motd) <(cat /etc/passwd).

After reporting a bug about that, Chet Ramey gave me the correct way to reach the initial goal:
cat <(eval cat /etc/\{passwd,motd})

6 thoughts on “Bash is weird.

  1. I’m not sure I follow you… First there was a pb with the planet (Ubuntu) that stripped the ‘cat
    or
    cat
    Give me the same result (output).

    This was maybe the weird thing you wanted to point out:
    $ echo

  2. I just don’t understand the need for the backslash, do you know why is there ?, actually I tested with and without and works just the same :), now I don’t know why it does actually work with the backslash :)

  3. Thanks a lot for the tip. I never expected it to be useful when I read it on the planet, not until diff

  4. Thanks a lot for the tip. I never expected it to be useful when I read it on the planet, not until diff <$(ls *.{h,cpp}) … complained about extra operands :-D.

Comments are closed.