Brace Expansion
Generate strings and sequences without loops — file operations, directory scaffolding, port ranges.
String Lists
echo {alpha,bravo,charlie}
# alpha bravo charlie
Brace expansion is processed before any other expansion. It generates words, not files — no filesystem lookup occurs.
for port in {22,53,80,443,636,3268}; do
timeout 1 bash -c "echo >/dev/tcp/10.50.1.50/$port" 2>/dev/null \
&& echo "port $port open" || echo "port $port closed"
done
Unlike ranges, comma lists let you specify exact non-sequential values. Use this for port scanning, VLAN lists, or any discrete set.
cp /etc/ssh/sshd_config{,.bak}
Expands to cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak. The empty first element plus the suffix generates original and modified filenames.
mv report.{txt,md}
Expands to mv report.txt report.md. Clean, single-command file renaming.
Numeric Ranges
echo {1..10}
# 1 2 3 4 5 6 7 8 9 10
{start..end} generates every integer in the range, inclusive on both ends.
touch log-{01..12}.txt
# Creates log-01.txt through log-12.txt
Leading zeros in the start value force zero-padding. The width matches the widest number in the range.
echo {0..100..10}
# 0 10 20 30 40 50 60 70 80 90 100
Third parameter is the increment. Useful for generating VLAN IDs, subnet offsets, or sample points.
for i in {10..1}; do echo "$i"; sleep 1; done; echo "done"
When start is greater than end, the range counts down.
Alphabetic Ranges
echo {a..z}
Generates all 26 lowercase letters. Works with uppercase {A..Z} too.
for disk in /dev/sd{a..d}; do
lsblk "$disk" 2>/dev/null && echo "---"
done
Combining a prefix with an alpha range produces device names, hostnames, or any letter-indexed identifiers.
Nested and Combined Expansion
echo {web,db,app}-{01,02}
# web-01 web-02 db-01 db-02 app-01 app-02
Adjacent brace expansions produce the cross product. Each element from the first set pairs with every element from the second.
echo vlan{10,20}-{sw,ap}-{01..03}
# vlan10-sw-01 vlan10-sw-02 vlan10-sw-03 vlan10-ap-01 ...
No limit on depth. The shell expands left to right, multiplying at each level.
mkdir -p project/{src/{main,test},docs/{api,user},config/{dev,staging,prod}}
Nested braces create a full directory hierarchy. mkdir -p handles intermediate directories. One command replaces a dozen.
Multi-file Operations
for f in switch-{01..04}.conf; do
printf "hostname %s\n" "${f%.conf}" > "$f"
done
Brace expansion generates the filenames. Parameter expansion (${f%.conf}) strips the extension for the hostname value.
diff /etc/netplan/config.yaml{.bak,}
Expands to diff /etc/netplan/config.yaml.bak /etc/netplan/config.yaml. Backup first, current second — diff shows what changed.
rm -f /tmp/capture-{5,6,9,10,11,13}.pcap
Comma-separated braces target exact items without globbing. No wildcard risk — only the listed files are affected.
mv {README,LICENSE,CONTRIBUTING}.md docs/
Expands to three separate arguments to mv. Cleaner than listing each file.
Combining with Other Expansions
# This does NOT work — brace expansion happens before variable expansion
end=5
echo {1..$end}
# Literal: {1..5} is NOT produced
# Workaround: use eval (carefully) or seq
eval echo {1..$end}
seq 1 "$end"
Brace expansion is processed first in the expansion order. Variables are not yet resolved. eval forces a second pass but introduces injection risk — prefer seq in scripts.
tar czf backup-$(date +%F).tar.gz /etc/{hosts,resolv.conf,hostname}
The date substitution runs independently. Brace expansion generates the three file paths. Both expansions compose cleanly because they operate on different parts of the word.
String Generation for Testing
printf "host-%s,192.168.1.%s,vlan%s\n" {1..5} {101..105} {10,10,20,20,30}
printf reuses its format string for each group of arguments. Combined with brace expansion, you can generate structured test data without loops.
echo {a..z}{0..9}{A..Z} | tr ' ' '\n' | shuf | head -20
Cross product of letters and digits produces 26x10x26 = 6760 three-character combinations. shuf randomizes, head samples. Not cryptographically secure — use for test data only.
See Also
-
Glob Patterns — wildcards match existing files, braces generate strings
-
Parameter Expansion —
${}operates on variables,{}generates text