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

Bashのコマンド置換、パイプ、プロセス置換の違い

Bashでコマンドの出力を別のコマンドに渡す際、コマンド置換、パイプ、プロセス置換のどれを使ったら良いか迷ったことはないでしょうか。
本記事ではそれぞれのデータ受け渡し方法の違いや、メリット・デメリットを解説します。

目次

  • 3者の違いの概要
  • コマンド置換
  • パイプ
  • プロセス置換
  • 3者の使い分け
  • まとめ

3者の違いの概要

コマンド置換、パイプ、プロセス置換は、いずれもあるコマンドの出力を別コマンドに渡せますが、その「橋渡し」の仕組みが大きく異なります。

  • コマンド置換: 出力を文字列(引数)として渡します。
  • パイプ: 出力を標準入力として渡します。
  • プロセス置換: 出力をファイルパス(のように見えるパイプ)として渡します。

コマンド置換

コマンド置換(Command Substitution)とは $(...) の形式で記述されるBashの展開の一つで、「コマンドの実行結果(標準出力)を、文字列としてその場所に置き換える」仕組みです。

例1:変数に格納

# Bash
# 変数に日付を代入
DATETIME=$(date +%Y%m%d%H%M)

例2:別のコマンドの引数として使用

# Bash
# アーカイブ名に日付を付与
tar cvzf uploads"$(date +%Y%m%d%H%M)".tar.gz uploads

注意点: コマンド置換は、内部のコマンドが完全に終了するまで出力をメモリに溜め込みます。そのため、出力が巨大な場合、メモリを圧迫するだけでなく、OSの制限(引数に渡せる最大文字数)を超えてしまい Argument list too long エラーが発生する可能性があります。

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

パイプ

パイプ(|)は、あるコマンドの標準出力を、次に続くコマンドの標準入力へと直接繋ぎます。

# Bash
# 容量順にカレントディレクトリのファイルをソート
du . | sort -n

メリット:

パイプはデータをストリーム(流れ)として扱います。最初のコマンドが1行出力するたびに次のコマンドへ渡されるため、たとえ数GBのログであってもメモリをほとんど消費せずに処理できます。

デメリット:

パイプは基本的に「1対1」の接続です。複数のコマンドの出力を、一つのコマンドに同時に流し込むことはできません。

Tips: xargsとの併用 パイプで受け取ったデータを「標準入力」ではなく「引数」として渡したい場合は、xargs を併用します。

# Bash
# 全てのログファイルでエラー検索
find . -type f -name '*.log' | xargs grep -i 'error'

プロセス置換

プロセス置換(Process Substitution)は <(...) もしくは >(...) の形で記載され、コマンドの出力を「ファイルパス」として扱えるようにする仕組みです。

# Bash
# echoの結果が/dev/fd/... という一時ファイルで渡される
diff -u <(echo "Hello World") <(echo "Hello Bash")

仕組み:

この /dev/fd/63 といったパスの正体はファイルディスクリプタ(パイプ)です。ディスク上に実際の一時ファイルは作成されず、かつデータストリームを受け渡しするため、高速かつ大容量データの処理にも向いています。

# Bash
ls -l <(echo "Hello World")
# 出力: lr-x------ 1 ... /dev/fd/63 -> 'pipe:[15054892]'

メリット:

最大の利点は、「ファイルしか受け付けないコマンド」に対して、複数のコマンド結果を同時に渡せる点です。

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

3者の使い分け

1. コマンドが受け取れる引数の種類で選ぶ

ファイル名しか受け取れない場合:

comm コマンドのように、複数のファイルを比較するコマンドにはプロセス置換が必須です。

# Bash
comm <(sort file1) <(sort file2)

標準入力を受け取れる場合:

grepsort などはパイプが最もシンプルです。

2. 出力コマンドの数で選ぶ

複数のコマンドの結果を合流させたい場合は、パイプではなくプロセス置換を使います。

# Bash
# 可読性が高く、複数の出力を同時に比較できる
diff -u <(ls dir1) <(ls dir2)

3. データサイズで選ぶ

  • 小規模(日付、単一の単語など): コマンド置換が適しています。
  • 大規模(ログファイル、リストなど): パイプまたはプロセス置換を使い、ストリーム処理を行うのが安全です。

まとめ

種類記述方法データの渡し方メモリ負荷複数出力の同時受け渡し
コマンド置換$(cmd)文字列(引数)高い(溜め込む)可能
パイプcmd | cmd2標準入力低い(流す)不可能
プロセス置換<(cmd)ファイルパス低い(流す)可能

3者の違いを理解することで、より効率的で堅牢なシェルスクリプトが書けるようになります。