Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

A Few Examples of Using Brace Expansion with Bash

a-few-examples-of-using-brace-expansion-with-bash.jpg

We'll go over examples with echo, how to use it for creating files and making multiple curl requests. It's a flexible feature!

Quick Jump:

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} outputs a b c d e
  • echo {10..1} outputs 10 9 8 7 6 5 4 3 2 1
  • echo {a..c}{1..4} outputs a1 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.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per year (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments