スタートアップCTOによるITエンジニアのためのブログ

Bashのブレース展開(Brace Expansion)をマスターして入力を爆速にする

Bashのブレース展開は、特定のパターンから複数の文字列を生成する非常に強力な仕組みです。これを知っているだけで、冗長なタイピングから解放されます。

目次

  • 概要とメリット
  • 基本的な構文
  • プリアンブルとポストスクリプト
  • 入れ子(ネスト)構造
  • エスケープ
  • 実用的な使い方の例
  • 展開の順序と変数
  • まとめ

概要とメリット

ブレース展開とは、Bashが持つ「7種類の展開」の1つです。波括弧 { } 内の要素をルールに基づいて展開し、複数の引数としてコマンドに渡します。

# Bash
echo {0..10}
# 出力
0 1 2 3 4 5 6 7 8 9 10

上記では、Bashが内部的に echo 0 1 2 3 4 5 6 7 8 9 10 というコマンドに変換してから実行しています。手動で10個の数字を打つ手間を省けるのが最大のメリットです。

基本的な構文

ブレース { } の中に、カンマ区切りのリストを入れるか、ドット2つの範囲を指定します。

1.カンマ区切り(リスト指定)

ブレース内に1つ以上のカンマで区切られた文字列を入れると、各文字列が展開されます。

# Bash
echo {apple,banana,cherry}
# 出力: apple banana cherry

⚠️ 注意: カンマの後にスペースを入れる(例: {a, b})と、Bashはブレース展開として認識せず、ただの文字列として扱います。スペース厳禁が鉄則です。

空の要素

カンマの前後に何も書かないと、空文字として扱われます。

# Bash
echo {,banana,cherry}
# 出力:  banana cherry(先頭に空文字が生成される)

これ単体では使い道がなさそうですが、後述のプリアンブルと組み合わせると、ファイル操作で威力を発揮します。

2.ドット2つ(範囲指定)

{x..y}の形式で、整数やアルファベットの連続したシーケンスを生成します。

# Bash
echo {1..5}
# 出力: 1 2 3 4 5

# マイナスや降順も可能
echo {3..-3}
# 出力: 3 2 1 0 -1 -2 -3

# 小文字シーケンス
echo {a..e}
# 出力: a b c d e

# 大文字降順シーケンス
echo {E..A}
# 出力: E D C B A

ゼロ埋め

整数による範囲指定では0 を付けることで、桁数を揃えてくれます。

# Bash
echo {01..10}
# 実行結果: 01 02 03 04 05 06 07 08 09 10

不連続なシーケンス

{開始..終了..増分}の形式で、増分の数だけスキップできます。

$ Bash
echo {1..10..2}
# 出力: 1 3 5 7 9

# アルファベットでも可能
echo {a..z..5}
# 出力: a f k p u z

範囲指定で生成出来ないもの

  • 日本語のようなマルチバイト文字のシーケンス:{あ..お}は「あ い う え お」とはならず、文字リテラルと解釈される。
  • 大文字と小文字を含むシーケンス:{a..Z}はブレース展開されず文字リテラルと解釈される(ただし、後述の入れ子構造を使い{{a..z},{A..Z}}とすれば可能)。
  • 整数以外のシーケンス:小数点のシーケンス{0.1..0.5}はブレース展開されず文字リテラルと解釈される(ただし後述のプレアンブルを使い0.{1..5}とすれば小数点シーケンス生成可能)。

プリアンブルとポストスクリプト

ブレースの直前(プリアンブル)や直後(ポストスクリプト)に文字列を置くと、展開されるすべての要素にその文字列が付与されます。

種類結果
プリアンブルpre{A,B}preA preB
ポストスクリプト{A,B}postApost Bpost
両方v{1,2}zv1z v2z

複数のブレースを並べると、左から順に組み合わされます。

# Bash
echo {a,b}{c,d}
# 出力
ac ad bc bd

上記の例は若干複雑ですが、以下の順番で展開されます。

  • {a,b}が展開されてa bになる。
  • a bにポストスクリプト{c,d}が後方接続され、a{c,d} b{c,d}となる。
  • 各{c,d}が展開されc dとなり、プリアンブルaとbがそれぞれ前方接続されac ad bc bdとなる。

入れ子(ネスト)構造

ブレースの中にさらにブレースを入れることも可能です。この場合、内側から外側へと展開されます。

# Bash
echo {A,B{1..3}}
# : A B1 B2 B3
  1. B{1..3}がB1 B2 B3に展開される。
  2. {A,B1,B2,B3}が展開される。

大文字と小文字を両方含めたい場合などに便利です。

# Bash
echo {{a..c},{A..C}}
a b c A B C

エスケープ

ブレースそのものを文字として使いたい場合は、クォート(推奨)かバックスラッシュを使用します。

# Bash
echo '{1..10}'
# 出力: {1..10}

echo \{1..10\}
# 出力: {1..10}

実用的な使い方の例

ファイルの一括作成

project ディレクトリ内に src, bin, doc というフォルダを作成。

# Bash
mkdir -p project/{src,bin,doc}

バックアップの作成

プリアンブルと「空の要素」を組み合わせて同じファイルパスをタイプする手間を省略します。

# Bash
cp /path/to/data.txt{,.bak}
# cp /path/to/data.txt /path/to/data.txt.bak と同じ意味

ファイル名の変更

プリアンブルとポストスクリプトを組み合わせ、元のファイルパスや拡張子を書く手間が省けます。

$ Bash
mv /path/to/{oldname,newname}.txt
# これは mv /path/to/oldname.txt /path/to/newname.txt と解釈されます

複数ログファイルの一括検索

ログローテーションで作成された複数のログファイルを検索したい際、個別に指定する手間を省けます。

# Bash
grep '404' access.log{,.1} <(zcat access.log.{2..7}.gz) 

*2~7日前の圧縮ログをBashのプロセス置換で展開しつつ、直近のログも同時に検索しています。

展開の順序と変数

ここは要注意ポイントです。ブレース展開は、変数展開($VAR)よりも先に実行されます。

$ Bash
END=10
echo {1..$END}
# 期待: 1 2 ... 10
# 実際: {1..10} ブレース展開はされず変数展開のみ

ブレースの中に変数を入れたい場合は、eval を使う必要があります(ただし、セキュリティ上の理由から慎重に扱うべきです)。

$ Bash
END=10
eval echo {1..$END}
# 出力: 1 2 3 4 5 6 7 8 9 10

また、${} という書き方はBashの「パラメータ展開」と誤認されるため、ブレース展開でドル記号を使いたい場合は注意しましょう。

# Bash
# echo $TERM $PATHとしたかったが誤り
echo ${TERM,PATH} 

# 出力: xterm-256color
# ブレース展開はされず$TERMのみパラメータ展開される

まとめ

Bashのブレース展開は、コマンドライン操作を効率化する第一歩です。最初は慣れないかもしれませんが、cpmkdir で少しずつ使ってみることで、日々の業務が驚くほどスムーズになります。