A Few Examples of Using Brace Expansion with Bash
We'll go over examples with echo, how to use it for creating files and making multiple curl requests. It's a flexible feature!
Brace expansion lets you do things like touch /tmp/deeply/nested/dir/{myfile,anotherfile}
and end up with (2) files in that
deeply nested directory. It’s quite handy from time to time!
It’s not POSIX compliant. It’s a Bash feature which works with zsh and other Bash’ish compatible shells.
# A Few Examples
Let’s go over a couple of use cases.
Hello world (literally):
$ echo {hello,world}
hello world
Anything within the braces will get “expanded”. It’s important not to add any spaces in between the braces and the comma.
This example is pretty boring because you could have also written echo hello world
to do the same thing, but it at least demonstrates how expansion works.
Creating multiple files or directories:
At the start of this post we saw that you can do touch {myfile,anotherfile}
to create 2 files with any name you want. I use that a lot, especially if the
file is in a long path.
Technically you can nest braces too:
$ echo {myfile-1,myfile-2{a,b},myfile-3}
myfile-1 myfile-2a myfile-2b myfile-3
Personally I don’t find myself doing that a lot but it’s handy to know it’s available to use.
Inserting ordered numbers or ranges into a file or directory name:
$ echo {1..5}
1 2 3 4 5
That’s kind of neat, we can pass in a range. Let’s make a few files doing that.
$ touch /tmp/myfile-{1..5}
$ ls /tmp/myfile-*
/tmp/myfile-1 /tmp/myfile-2 /tmp/myfile-3 /tmp/myfile-4 /tmp/myfile-5
The range doesn’t need to be inserted at the end of the file name too. You can put it anywhere you want within the path.
Combining ranges together:
$ mkdir -p /tmp/demo/{1..3}/{-5..-1}-mydir
$ tree /tmp/demo
/tmp/demo
├── 1
│ ├── -1-mydir
│ ├── -2-mydir
│ ├── -3-mydir
│ ├── -4-mydir
│ └── -5-mydir
├── 2
│ ├── -1-mydir
│ ├── -2-mydir
│ ├── -3-mydir
│ ├── -4-mydir
│ └── -5-mydir
└── 3
├── -1-mydir
├── -2-mydir
├── -3-mydir
├── -4-mydir
└── -5-mydir
18 directories, 0 files
That could be handy if you’re making multiple ordered directories. This demonstrates that you can use negative ranges too.
Other types of ranges:
echo {a..e}
outputsa b c d e
echo {10..1}
outputs10 9 8 7 6 5 4 3 2 1
echo {a..c}{1..4}
outputsa1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4
For the last one it’s important there’s no spaces in between the pairs of braces.
Combining file globbing and brace expansion:
In a previous post about recursively printing files content we landed on using file globbing.
You can use that with brace expansion to limit which file types or specific files should be printed. Here’s 2 examples you could run against my example Flask / Docker project:
# Match all Python and Markdown files.
tail -n+1 **/*.{py,md}
# Match all __init__.py and views.py files.
tail -n+1 **/{__init__,views}.py
As long as 1 or more files exist for all matching patterns it will list them out. If you try to run the above command when any of the matching file patterns don’t exist then your shell will throw a no matches found error.
Sometimes replacing loops, such as with curl:
For example, let’s say you wanted to make a couple of curl
requests to see
what the weather is like in both California and New York:
curl https://wttr.in/{sacramento,albany}
That will make (2) HTTP requests in a row as if you ran them right after each other.
That site supports using zip codes too so you could technically use a
{XXXXX..XXXXX}
range of zip codes if you wanted.
Or, I’ve done videos in the past about
https://httpstat.us which lets you easily test different HTTP status codes.
You could do curl httpstat.us/{500..504}
to get back a list of status code
responses for specific errors as a 1 liner.
I might not use brace expansion every day but it’s the perfect tool for when you need it.
Knowing if a command supports brace expansion:
If the command supports passing multiple arguments in as input then it should
work. For example echo
, touch
, stat
, rm
, mkdir
, curl
and many
others support that.
If the command does not support it then typically the first argument will be
used and the rest will be ignored. For example the mkscript
tool I wrote doesn’t support it
so if you ran mkscript a b
or mkscript {a,b}
then only a
will be created.
# Demo Video
Timestamps
- 0:18 – Creating, verifying and deleting a few files
- 0:55 – How do you know if a command supports brace expansion?
- 1:33 – Echoing hello world
- 2:11 – Nested brace expansions
- 3:00 – Different types of ranges (numbers, characters, reverse)
- 4:03 – Combining multiple ranges together
- 5:01 – Creating an ordered list of files or directories
- 6:45 – Using it with file globbing to filter printed files
- 9:33 – Using it to get the weather in multiple cities
- 10:48 – Using it to test multiple HTTP status codes
What’s your favorite use case for brace expansion? Let me know below.