Brace Expansion

Before the Bash shell executes a command in a terminal window or a line in a script, it checks whether it needs to perform any substitutions on the command. Variable names are replaced by their values, aliases are replaced by the commands they’re shorthand for, and any expansion is performed. Brace expansion is one form of expansion supported by Bash.

Brace expansion is available in modern shells, but it might be missing from some old shells. If you’re going to use brace expansion in scripts, make sure that you invoke a shell that supports brace expansion, such as Bash:

We’ll be using Bash for our examples.

Generating lists of strings might seem more of a novelty than a benefit, but it does offer some functionality that can save time and keystrokes. Often, it can provide a simple and elegant solution to a problem or requirement.

Simple Expansions

A brace expansion is contained between a pair of braces “{}”. It can be a list of comma-separated items or a range specifier. Spaces are not permitted inside the braces unless you’ve wrapped the string in quotation marks “".”

For a comma-separated list, the expansion process takes each element in turn and passes it to the calling command. In this example, it’s echo that simply prints them in the terminal window. Note that the commas are ignored.

A list can be words or digits.

The order of the list elements is completely arbitrary.

An expansion range has a start and an end character connected with two periods ” .. ” without any whitespace. All of the missing list elements are provided automatically by the expansion so that the entire range from start character to end character is created.

This will print the digits from 1 to 10.

The numbering is arbitrary. It does not have to start at one.

Ranges can be specified so that they run backward. This will generate a list from five down to one.

Ranges can include negative numbers.

As we previously pointed out, a range has a start and an end character. It doesn’t have to be a number. It can be a letter.

The letters can run backward, too.

Using Brace Expansion with Loops

You can use brace expansion with ranges in loops in scripts.

Brace expansion ranges let you use characters as the loop variable.

Loops are usually used in scripts, but there’s nothing to stop you from typing them into the command line to see what will happen.

Concatenating and Nesting

Two adjacent expansions don’t act independently one after the other. They interoperate. Each element in the first expansion is acted on by each element in the second expansion.

Expansions can also be nested. A nested expansion will act on the element immediately preceding it.

You can also nest expansions by creating a comma-delimited list of range expansions.

Preamble and Postscript

You can place text before and after a brace expansion to have that text included in the results of the expansion. Text put in front of an expansion is called the preamble, while text placed behind a brace expansion is called the postscript.

This command uses a preamble.

This example uses a postscript:

And this command uses both.

Expanding File Names and Directories

As you’ve probably guessed by now, one of the main uses of brace expansions is to create file and directory names that can be passed to other commands. We’ve been using echo as a convenient way to see exactly what happens when an expansion is triggered. You can substitute any command that takes filenames or directory names as input and use brace expansion with it.

To quickly create some files, use touch:

If you have many files with the same base name but different file extensions and you want to perform an operation on a subset of them, brace expansions can help. Here, we’re compressing a subset of files that have “program” as the basename into a ZIP file called “source-code.zip.”

Development directories contain lots of files that will have the same basename as your main program. Usually, you don’t want to back up or distribute files like “.o” object files. This is a neat way to only include the file types of interest.

This command will make a copy of a file and append “.bak” to it, making a backup copy of the original file. An interesting point to note is that the brace expansion contains a comma-separated list, but the first element is empty. If we hadn’t included the comma, the expansion wouldn’t have taken place.

To perform some action on two files in different directories, we can use a brace expansion in the path to the files.

In this example, the “brace” directory contains two subdirectories, one called “new” and one called “old.” They contain different versions of the same set of source code files. We’ll use the diff program to see the differences between the two versions of “prog-1.c.”

If you have a standard skeleton of directories that you need to create at the start of a project, you can create them quickly using brace expansion. The  mkdir -p (parent) option creates any missing parent directories when a child directory is created.

You can use brace expansion with wget to download multiple files.

In this command, we’re going to download files from two directories, called “test1” and “test2.” Each directory holds two files called “picture1” and “picture2.”

Listing the files shows you the files that were retrieved and how wget renames files to avoid name clashes with existing files.

Embrace the Brace

Give it a try and it just might find its way into your set of command-line go-to tricks.