LearnLinux FoundationsBash Shell Environment

Brace Expansion

echo - a hands-on Linux lab on a real virtual machine.

Turn one line into many with brace expansion. Build a comma list, glue fixed text around it, count a range with steps and zero padding, multiply two braces into a cross product, and use the mkdir and cp backup tricks. Brace expansion is pure text and runs first, before variables and wildcards, so it builds names whether the files exist or not: this lesson teaches the shapes and the two gotchas that bite beginners.

Say you need three folders: src, test, and docs. You could type three mkdir commands. Or you could type one, and let the shell fan it out for you.

The shell has a quiet trick where a pattern in curly braces { } turns into a whole list of strings before the command even runs. It is called brace expansion, and once you see it you will reach for it every day. Best of all, you can watch it happen in plain sight.

The black boxes in this lesson are a practice terminal: a safe sandbox that checks the one command each step teaches, so you cannot break anything. Brace expansion is pure text, so every output here is exact and will look the same on any machine. We will use echo, the command that simply prints whatever you hand it, so you can SEE what the braces turned into.

Brace expansion takes a pattern like {a,b,c} and generates several separate strings from it: one per item inside the braces. It happens purely by text. The shell rewrites your line first, then runs the command on the result.

Because it is invisible when a real command swallows the output, the honest way to learn it is to print it. echo prints its arguments and nothing else, so echo plus a brace pattern shows you exactly what the shell built.

Start with a plain comma list. Before you press Enter, decide what you expect to see. Then run it:

echo {a,b,c}

prompt: student@linuxcamp:~$ answer: echo {a,b,c} output: a b c hint: Type echo, a space, then the three letters inside braces with commas: echo {a,b,c}

The {a,b,c} became three separate words, a b c, and echo printed them with spaces between. The braces and commas are gone: the shell used them as instructions, not as text. That is the whole idea. One brace pattern, three arguments.

Brace expansion is even more useful when there is fixed text before or after the braces. Whatever sits outside the { } gets glued onto every item inside it. This is how one short pattern names a batch of related files.

Put a word in front and a suffix behind, and watch each item pick up both:

echo file{1,2,3}.txt

prompt: student@linuxcamp:~$ answer: echo file{1,2,3}.txt output: file1.txt file2.txt file3.txt hint: The word file goes before the braces, .txt after: echo file{1,2,3}.txt

Each item, 1 2 3, was wrapped in the same fixed text: file on the left, .txt on the right. So one pattern produced three tidy filenames. Notice you never had to repeat the word file or the .txt. That is the labor brace expansion saves.

Listing items one by one is fine for three. For twenty it is misery. When your items are a simple sequence, use two dots instead of commas: {1..5} means every number from 1 to 5. This is a range, and the shell fills in the middle for you.

Ask for one through five without typing the ones in between:

echo {1..5}

prompt: student@linuxcamp:~$ answer: echo {1..5} output: 1 2 3 4 5 hint: Two numbers with two dots between them, no commas: echo {1..5}

{1..5} filled in 1 2 3 4 5 on its own. The two dots mean "count from the first to the last," so you only name the endpoints. Ranges work on letters too: {a..e} gives you a b c d e. Anywhere you would have typed a boring sequence, a range does it in a few characters.

Ranges have two refinements worth knowing, because both come up in real work.

First, zero padding: if you pad the first number with a leading zero, every result keeps that width. {01..03} gives 01 02 03, which is exactly what you want when files must sort in order (file01 before file10).

Second, a step: add a third number to jump in bigger increments. {1..10..2} counts from 1 to 10 in steps of 2. Run the step in action:

echo {1..10..2}

prompt: student@linuxcamp:~$ answer: echo {1..10..2} output: 1 3 5 7 9 hint: Start, end, then a third number for the step, all split by two dots: echo {1..10..2}

The third value, 2, is the step: the shell started at 1 and jumped by two each time, so it printed 1 3 5 7 9 and stopped before passing 10. Swap the step for 3 and you would get 1 4 7 10. And remember zero padding from a moment ago: echo {01..03} prints 01 02 03, widths preserved. Two small knobs, both handy.

Here is the move that feels like magic. Put two brace patterns next to each other and the shell pairs every item of the first with every item of the second. This is called a cross product: each combination, once.

Two letters times two numbers should give you four results. Decide which four before you run it:

echo {A,B}{1,2}

prompt: student@linuxcamp:~$ answer: echo {A,B}{1,2} output: A1 A2 B1 B2 hint: Two brace groups touching, no space between them: echo {A,B}{1,2}

Every item on the left, A and B, was joined to every item on the right, 1 and 2: A1 A2 B1 B2. Two times two is four combinations, and the shell wrote them all. This is how one line lays out a grid of names, like {dev,prod}-{web,db} for four server names, without you spelling out a single one.

Everything so far used echo so you could watch. But brace expansion works in front of ANY command, because the shell expands the braces first and then hands the finished list over. Here is the example that opened the lesson.

mkdir makes directories. Feed it a brace pattern and it makes them all in one line. This creates three folders inside a project folder at once:

mkdir project/{src,test,docs}

prompt: student@linuxcamp:~$ answer: mkdir project/{src,test,docs} output: hint: mkdir, a space, then the parent path with the three names in braces: mkdir project/{src,test,docs}

No output means it worked, the usual quiet success of mkdir. Behind the scenes the shell rewrote your line into mkdir project/src project/test project/docs, three arguments, then ran it. The braces did the typing for you. This one pattern, command path/{a,b,c}, scaffolds a whole project layout in a single keystroke's worth of thought.

There is a famous shortcut every engineer eventually learns: making a quick backup copy. cp copies a file, and a brace pattern with an empty first item gives you the original name AND a backup name from one word.

The pattern {,.bak} has two items: an empty one (before the comma) and .bak (after it). Glued onto file.txt, it becomes file.txt and file.txt.bak. So cp sees the source and the destination, and copies one to the other:

cp file.txt{,.bak}

prompt: student@linuxcamp:~$ answer: cp file.txt{,.bak} output: hint: cp, the filename, then the empty-plus-.bak braces stuck to the end: cp file.txt{,.bak}

The empty first item expanded to just file.txt. The second, .bak, expanded to file.txt.bak. So the shell built cp file.txt file.txt.bak: copy the file to a name one suffix longer. That is a one-line backup before you edit something risky. Odd-looking the first time, muscle memory forever after.

One rule ties the lesson together. Brace expansion happens FIRST, before the shell looks at variables, before ~ for your home folder, and before * wildcards. And it is purely textual: it builds names whether or not those files exist. That is the key difference from the * wildcard you will meet next, which only matches files that are really there.

Because it is textual, two small things trip up nearly everyone. Both are worth seeing once so they never cost you time.

A space inside the braces breaks the whole thing. The shell only treats { } as a pattern when there are no spaces, so a stray space turns it back into ordinary text:

echo {a, b}

prompt: student@linuxcamp:~$ answer: echo {a, b} output: {a, b} hint: Type it exactly with a space after the comma to see it stay literal: echo {a, b}

Instead of a b, you got the literal text {a, b}, braces and all. The space told the shell "this is not a brace pattern," so it left every character alone. The fix is simple once you know it: no spaces inside the braces. The second gotcha is just as quiet. A single item like {a}, with no comma and no .. range, has nothing to expand, so echo {a} prints the literal {a}. Brace expansion needs at least two items or a range to do anything.

Scaffolding off. No command is printed this time. You have every piece you need.

You want to print four names in a grid: the letters A and B, each paired with the numbers 1 and 2, so A1 A2 B1 B2. Use echo so you can read the result, and use two brace groups so the shell builds every pairing for you. No commas-only list, no spaces inside the braces.

prompt: student@linuxcamp:~$ answer: echo {A,B}{1,2} output: A1 A2 B1 B2 hint: Two brace groups touching, one with the letters, one with the numbers, and echo in front. Think echo, then {A,B}, then {1,2}.

That is the cross product from memory. {A,B} supplied the letters, {1,2} supplied the numbers, and touching them with no space told the shell to pair every combination: A1 A2 B1 B2. Same shape on any machine, because brace expansion is pure text. You recalled two brace groups and joined them, which is exactly the muscle the real machine will ask of you.

You earned this cheat sheet. Every row is a pattern you just ran:

And the two rules that keep you out of trouble: no spaces inside the braces, and a single item like {a} stays literal. Brace expansion runs first, before variables and wildcards, and it is pure text: it builds names whether the files exist or not.

The star wildcard * looks similar but is the opposite: it only matches files that already exist on disk. Brace expansion invents names from text; * finds names that are really there. That contrast is the next idea in this module, and knowing brace expansion first makes it click.

The practice terminal has shown you the shape of brace expansion. You can build a comma list, glue text around it, count a range with steps and padding, multiply two braces into a grid, and use the mkdir and backup tricks that make it worth learning. Every one of those you typed yourself.

The Bash Environment module ends with one real Linux machine, the Bash Environment capstone mission, and that is where you use brace expansion for real. A VM boots just for you, with its own live shell. It hands you objectives that use exactly what you practiced across this module: variables, exports, the command lookups, expansions, quoting, and the braces you just learned. One difference from here: the mission shows no commands. You read the objective, you recall the pattern, you type it. That recall is what makes it stick.

Finish the other Bash Environment lessons, then go fan out a real command line for yourself.

Practice Brace Expansion in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.