Using Brace Expansion in Bash Shell
Brace expansion {..}
is one of the most underutilized but awesome shell features in Linux.
You can use it to print sequences of numbers and letters. Add two integers or letters separated by two dots in curly braces and see the magic.
In its simplest form, take this for example:
echo {1..10}
Can you guess the output?
1 2 3 4 5 6 7 8 9 10
The output sequence is printed in the same line with a space between them.
Let me give you some more examples of brace expansion so that you understand its functioning better.
Brace expansion examples
Let's say you want to get a reverse sequence of numbers from 7 to 1.
abhishek@LHB:~$ echo {7..1}
7 6 5 4 3 2 1
You can add leading zeroes:
abhishek@LHB:~$ echo {01..10}
01 02 03 04 05 06 07 08 09 10
You can use the brace expansion in the form of {x..y..z}
to generate values from x till y while incrementing by z.
Let's say you want a sequence of even numbers till the number 15.
abhishek@LHB:~$ echo {0..15..2}
0 2 4 6 8 10 12 14
Or get an odd number sequence:
abhishek@LHB:~$ echo {1..15..2}
1 3 5 7 9 11 13 15
You can go in any incremental steps:
abhishek@LHB:~$ echo {100..1000..99}
100 199 298 397 496 595 694 793 892 991
It can also take negative numbers:
abhishek@LHB:~$ echo {3..-4}
3 2 1 0 -1 -2 -3 -4
Using sequence of letters
So far I have only used sequences of numbers. But you can use it to generate sequences of letters as well.
abhishek@LHB:~$ echo {A..H}
A B C D E F G H
You can go reverse as well:
abhishek@LHB:~$ echo {H..A}
H G F E D C B A
Or go into incremental or decremental steps:
abhishek@LHB:~$ echo {H..A..2}
H F D B
You can also use small case letters the same way:
abhishek@LHB:~$ echo {a..f}
a b c d e f
Practical usage of brace expansion
So far, I have just shown examples of creating sequences with brace expansion in the bash shell.
But they are not practical examples. You can put it to some actual good use. Let me share a few such examples.
Create multiple files with similar names
Create files with a particular name pattern:
abhishek@LHB:~/test$ touch file_{1..10}.txt
abhishek@LHB:~/test$ ls
file_10.txt file_2.txt file_4.txt file_6.txt file_8.txt
file_1.txt file_3.txt file_5.txt file_7.txt file_9.txt
Create backup file
When you are about to edit a config file, it is recommended to make a backup. The general convention is to add a .bak
extension to the original filename. This signifies that it's a backup of the given filename.
cp -p long_filename.txt long_filename.txt.bak
That's cool but let's use the brace expansion:
cp -p long_filename.txt{,.bak}
Yupe! This {,text}
is not the usual {X..Y}
pattern but it's a useful one you should know.
The -p
option of the cp command preserves the file properties like ownership, timestamps, etc.
Use multiple braces
You can use multiple braces to create files with similar names and different extensions. That's only one example of using multiple braces.
abhishek@LHB:~/test$ touch {a,b,c}.{hpp,cpp}
abhishek@LHB:~/test$ ls
a.cpp a.hpp b.cpp b.hpp c.cpp c.hpp
abhishek@LHB:~/test$
Using brace expansion in path
Let's say you have a similar directory structure with only a slight change. Brace expansion can be helpful here.
mv project/{new,old}/dir/file
The above command is equivalent to:
mv project/new/dir/file project/old/dir/file
Not everything can be expanded
That goes without saying. You are looking to create sequences so it should be something that could be created into sequences. If you use a weird combination, it won't be expanded.
abhishek@LHB:~$ echo {1..Z}
{1..Z}
You cannot use decimal points.
abhishek@LHB:~$ echo {1..5..0.5}
{1..5..0.5}
It may generate weird results for some weird combinations:
abhishek@LHB:~$ echo {a..F}
a ` _ ^ ] [ Z Y X W V U T S R Q P O N M L K J I H G F
Conclusion
When you are new to it, brace expansion will feel cumbersome. I mean, how long does it take to type them all by hand?
But once it gets into your muscle memory, it takes your Linux command skills to another level.
So, try and use brace expansion in your shell scripting as much as possible.