Search code examples
linuxbashshellglobbrace-expansion

How to use curly braces in a shell (bash)


I'm currently trying to reproduce basic shell behaviours, and more specifically globbing behaviours. I was testing commands with curly braces in it and found this behaviour that I don't understand. First, the content of the directory I'm working in is the following :

1abc 2abc 3abc abc1 abc2 abc3

Then, I typed the following command : ls {[1-3],[a-c]}*, and it returned me all the files above as expected.

And finally, I tried this command : ls {{,[1-3]},[a-c]}*, which as you can see, has imbricated curly braces. Now what I don't understand is the return of this command, because it gave me this : 1abc 1abc 2abc 2abc 3abc 3abc abc1 abc1 abc2 abc2 abc3 abc3

As you can see, all the files were returned two times, and I can't figure out how the shell is interpreting this.

I hope my explanation was clear.


Solution

  • The string {{,[1-3]},[a-c]}* is an expression interpreted as brace expansion that consists of the following patterns:

    • "emptiness" ({,),
    • [1-3], and
    • [a-c].

    The * character (meaning "every filename in the given directory") is applied for each of them:

    *       => 1abc  2abc  3abc  abc1  abc2  abc3
    [1-3]*  => 1abc  2abc  3abc
    [a-c]*  => abc1  abc2  abc3
    

    The fact that you have nested the expressions doesn't change the meaning that it is just a list of the three patterns. The same effect could be achieved with a simpler expression like {,[1-3],[a-c]}*, or another "list of lists" like {,{[1-3],[a-c]}}*.

    If you pass the expression to echo, it will print all the characters from the lines above, one after another:

    $ echo {{,[1-3]},[a-c]}*
    1abc 2abc 3abc abc1 abc2 abc3 1abc 2abc 3abc abc1 abc2 abc3
    

    But ls sorts the entries alphabetically by default:

    $ ls {{,[1-3]},[a-c]}*
    1abc  1abc  2abc  2abc  3abc  3abc  abc1  abc1  abc2  abc2  abc3  abc3