I created three files in my directory using the command touch inv{1..3}.txt. Now I used two commands and their output is pretty much the same. Those two commands are ls inv[13].txt and ls {1,3}.txt.
So how are these two different? How are square brackets different compared to braces? Also I was googling for "linux [..]", but couldn't find anything, so could I know as to what these things are called in linux terminology?
Thanks
32 Answers
{}is called brace expansion. It has two forms:{x..y}and{x,y}, replacexandywith any alphabetic or numeric value.In the first form,
{x..y}will be expanded to all values fromxtoy, inclusive. For example,{2..5}will be expanded to2,3,4,5.In the second explicit form,
{x,y}will be expanded to onlyx,y. For example,{2,5}will be expanded to2and5.If no expansion is possible, the pattern is treated literally e.g. in
{a..3}.Important thing to note is that the brace expansion will be done (if possible) irrespective of any file match, while in file creation/matching.
[]is known as a pathname expansion (or globbing) pattern. Unlike brace expansion you can only use it while matching filenames, it will be treated literally if you use it while creating files.It has two forms:
[xyz...]and[x-y].In the first form, it will match any single character inside the square brackets separately I.e. each character is treated individually. So for
[25].txtit will match a file named2.txtor5.txtin the current directory, while for[245].txtit will match any file named2.txtor4.txtor5.txt.In the second form, a range expansion is done first before matching individually, if possible otherwise treated literally. So for
[2-5]. txt, it will match any file named2.txtor3.txtor4.txtor5.txt. If the range can't be expanded, it will treated literally e.g. in case of[a-3].txt.
An important behavioral difference between these two is when there are more patterns to match while less actually is matched. As the brace expansion is done no matter what, it will show error that certain file(s) does not exist while pathname expansion will match whatever possible without any error for the rest:
$ ls {1..4}.txt
ls: cannot access 4.txt: No such file or directory
1.txt 2.txt 3.txt
$ ls [1-4].txt
1.txt 2.txt 3.txtPortability Note:
The [] pathname expansion operator is defined by POSIX hence portable among Bourne shell and derivatives.
The brace expansion, {}, is not defined by POSIX hence is not portable among all shells. For example, dash (sh in Ubuntu) does not have this. It was borrowed from csh and will work on certain shells only e.g. bash, zsh, ksh93, fish. Make sure the shell you are using supports this before implementing.
Example:
$ touch {1..3}.txt
$ ls {1..3}.txt
1.txt 2.txt 3.txt
$ ls {1,2,3}.txt
1.txt 2.txt 3.txt
$ ls {1..4}.txt
ls: cannot access 4.txt: No such file or directory
1.txt 2.txt 3.txt
$ ls {a..3}.txt
ls: cannot access {a..3}.txt: No such file or directory$ ls [123].txt
1.txt 2.txt 3.txt
$ ls [1-3].txt
1.txt 2.txt 3.txt
$ ls [1-4].txt
1.txt 2.txt 3.txt
$ ls [a-3].txt
ls: cannot access [a-3].txt: No such file or directory 4 The key difference between the two forms is illustrated here:
$ ls inv[15].txt
inv1.txt
$ ls inv{1,5}.txt
ls: cannot access 'inv5.txt': No such file or directory
inv1.txtinv[15].txt is a glob and will expand the a list of matching files on your file system. This is pathname expansion.
inv{1,5}.txt expands to inv1.txt and inv5.txt regardless of what files are actually on your file system. This is brace expansion.