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

Bashシェル展開(Expansion)の全体像

Bashがコマンドを実行する際、入力した文字列がそのまま実行されるわけではありません。実行前に「展開(Expansion)」というプロセスを経て、文字列が書き換えられます。

この記事では、Bashにおける展開の種類とその優先順位について解説します。

目次

  • 展開とは
  • 展開の種類
    • ブレース展開
    • チルダ展開
    • パラメータ展開(変数展開)
    • コマンド置換
    • 算術展開
    • プロセス置換
    • 単語分割
    • パス名展開(ワイルドカード)
  • クォートによる展開抑止
  • 展開の順序
  • 展開とコマンド実行の順序
  • まとめ

展開とは

展開とは、入力された文字列を特定のルールに基づいて変換・置換するプロセスのことです。

例えば、ls *.txt と入力したとき、シェルは *.txt を実際のファイル名リストに置き換えてから ls コマンドに渡します。この「置き換え」の作業すべてを展開と呼びます。

展開の種類

Bashには8種類の展開があります。

1. ブレース展開

{} 内のカンマ区切りの文字列や範囲を元に、複数の文字列を生成します。

# Bash
echo log.{1,2,3}
# 結果: log.1 log.2 log.3

ブレース展開については「Bashのブレース展開(Brace Expansion)をマスターして入力を爆速にする」で詳しく紹介しています。

2. チルダ展開

~ をホームディレクトリの絶対パスに置き換えます。

# Bash
echo ~/Documents  # 結果: /home/user/Documents

その他にも、他のユーザのホームディレクトリや、1つ前にいたディレクトリに置き換える機能もあります。

チルダ展開については「Bashチルダ展開(Tilde Expansion)による高速ディレクトリ操作」で詳しく紹介しています。

3. パラメータ展開(変数展開)

$ に続くパラメータ(変数)を、その値に置き換えます。

# Bash
name="Alice"
echo "Hello, ${name}"
# 結果: Hello, Alice

値を単純に参照するだけでなく、様々な文字列操作によって置き換えることも可能です。

パラメータ展開については「Bashのパラメータ展開(変数展開)をマスターしよう」で詳しく紹介しています。

4. コマンド置換

$(command) の形式で、コマンドの実行結果(標準出力)に置き換えます。

# Bash
echo "今日は$(date)" 
# 結果: 今日は2026年 2月 15日 ...

コマンド置換の結果は、別のコマンドの引数に使ったり、変数に代入することが可能です。

コマンド置換については「Bashのコマンド置換(Command Substitution)徹底解説」で詳しく紹介しています。

5. 算術展開

$((expression)) の形式で、数式の計算結果に置き換えます。

# Bash
echo $((1 + 2 * 3)) 
# 結果: 7

算術展開を使って2進数を使ったビット演算を行ったり、ループの処理状況を表示するといったことも可能です。

算術展開については、「Bashの算術展開(Arithmetic Expansion)を使いこなそう」で詳しく紹介しています。

6. プロセス置換

コマンドの出力をファイルのように扱えるようにします。

# Bash
diff <(ls dir1) <(ls dir2) 
# dir1とdir2のファイル一覧を比較

プロセス置換を使うと、引数にファイルしか渡せないコマンドに対して、別のコマンドの処理結果を渡すことが可能になります。

プロセス置換については、「Bashのプロセス置換の使い方:一時ファイルとおさらばする技術」で詳しく紹介しています。

7. 単語分割

パラメータ展開、コマンド置換、算術展開の結果に空白が含まれる場合、それらを個別の引数として分割します。

# Bash
fruits='apple orange banana'
printf ' <%s>' $fruits
# 結果:  <apple> <orange> <banana>

※ダブルクォートで囲むと、この分割を抑制できます。

カンマ(,)など空白以外の文字で単語を分割し、文字列に含まれる複数の要素をループするといったことも可能です。

単語分割については、「Bashの単語分割(Word Splitting)を使いこなそう」で詳しく紹介しています。

8. パス名展開(ワイルドカード)

*? などのワイルドカードを含むパターンを、一致するファイル名のリストに置き換えます。

# Bash
ls *.jpg  # 結果: image1.jpg photo.jpg など

パターンマッチングの設定を変えることで、隠しファイル(ドットファイル)を表示したり、ディレクトリを再帰的に検索するようにすることも可能です。

パス名展開については「Bashのパス名展開(Pathname Expansion)でワイルドカードを使いこなそう」で詳しく紹介しています。

クォートによる展開抑止

展開をさせたくない場合は、クォート(引用符)を使用します。

記号名称挙動
' 'シングルクォートすべての展開を無効化する(最強の抑止)。
" "ダブルクォートパラメータ展開、コマンド置換、算術展開以外を抑止する。

通常はダブルクォートで変数を囲い、意図しない展開を防ぐのがベストプラクティスです。

# Bash
# ダブルクォートで単語分割を抑止
file='my file.txt'
printf ' <%s>' "$file"
# 結果:  <my file.txt>

展開の順序

Bashは以下の順序で展開を行います。

  1. ブレース展開
  2. チルダ展開、パラメータ展開、算術展開、プロセス置換、コマンド置換(これらは同等の優先度で出現順に左から行われる)
  3. 単語分割
  4. パス名展開
  5. クォート除外(最終的にクォート記号自体が取り除かれる)

この順番を知ることで、「なぜブレース展開内で変数が使えないのか」といった謎が解けます。

# Bash
# 変数展開してからブレース展開したいという意図だが失敗
extensions='txt,csv'
echo {$extensions}
# 結果: {txt,csv}

展開とコマンド実行の順序

シェルがコマンドを実行するまでの大きな流れは以下の通りです。

  1. 解析: コマンドラインを読み込み、トークンに分ける。
  2. 展開: 上記のルールに従って文字列を置換する。
  3. リダイレクト: <> の処理を行う。
  4. 実行: 展開後の文字列を引数として、実際のコマンドを起動する。

重要: コマンド側(lsやechoなど)は、展開が終わった後の「完成した文字列」しか受け取りません。

まとめ

Bashの展開を理解することは、シェルスクリプトのバグを防ぎ、複雑なワンライナーを使いこなすための第一歩です。特に「展開の順序」「クォートの影響」を意識するだけで、シェルの挙動がぐっと予測しやすくなります。