Linux 講座 / 標準入力・出力、リダイレクションとパイプの理解

シェルのコマンドには通常、標準入力(stdin)、標準出力(stdout)、標準エラー(stderr)という三つの経路があります。Bashでは<はファイルを入力として、>と>>は標準出力をファイルに、2>はエラーをファイルに送ります。|は一つのコマンドの出力を次のコマンドの入力に接続します。どの経路がどこに向かうか分かれば、結果が画面に表示されない理由も説明できます。

ここでは標準入力・出力・エラーがどのファイルやコマンドに向かうかを扱います。成功・失敗に応じて次のコマンドを選択する&&・||の実行条件はシェルの実行フローで区別して説明します。

三つの標準ストリームの区別

シェルでプロセスが最初に使用できる三つの標準ファイルディスクリプタは番号でも表現されます。キーボード・画面と接続されるのが一般的ですが、リダイレクトやパイプによって他の場所に変わることがあります。

番号 名前 主な役割
0 標準入力(stdin) コマンドが読み込むデータ
1 標準出力(stdout) 正常な結果
2 標準エラー(stderr) 診断・エラーメッセージ

2つの出力はターミナル上で一緒に表示されても、異なる通路です。だから>で正常な結果だけを保存しても、エラーメッセージは依然として画面に残ることがあります。番号はコマンドラインに付く2>のような表記を理解する際に重要です。

実習用ファイルを作る

この講座の例はBashを基準にしています。ホームディレクトリにlinux-course-14-practiceが既に存在する場合は、別の名前を選んでください。新しいディレクトリを作成できなかった場合は、次のコマンドを実行しないでください。>はファイルが存在する場合、その内容を空にして新たに書き込みます。

mkdir ~/linux-course-14-practice
cd ~/linux-course-14-practice
pwd

位置を確認した後、2行を保存し、>>に1行を追加します。>>はファイルの末尾に追加する方式です。

printf 'alpha\nbeta\n' > source.txt
printf 'gamma\n' >> source.txt
cat source.txt

最後の出力は順にalpha、beta、gammaです。画面に表示された文字列をファイルに保存するか、既存のファイルの後ろに追加するかを先に決めてから演算子を選んでください。

ファイルを入力として渡すか、正常な結果を保存する

<はファイルを標準入力に接続します。wc -l < source.txtはファイル名の引数を渡す代わりに入力ストリームを提供するので、数字3のみを出力します。一方でwc -l source.txtは通常、数字の後にファイル名も表示します。

wc -l < source.txt

標準出力を別ファイルに保存するには>を使用します。次のコマンドの後、画面には一致する行が表示されず、matches.txtにbetaが保存されます。

grep 'beta' source.txt > matches.txt
cat matches.txt

cat matches.txtがbetaを出力するか確認してください。リダイレクト先のファイルはコマンドが本格的に実行される前に開かれるため、重要な既存ファイルに>を書き込むと元の内容を失う可能性があります。

エラー出力を別に扱う

存在しないファイルを参照すると、lsは診断メッセージを標準エラーに出力します。次のコマンドはエラーのみをerrors.txtに保存します。新しい練習フォルダでabsent-14.txtが存在しないことを前提とします。

ls absent-14.txt 2> errors.txt
cat errors.txt

エラーメッセージはロケールによって異なりますが、ファイルが存在しないことが表示されるはずです。標準出力とエラーを1つのファイルにまとめるにはBashでコマンド > all.txt 2>&1のように記述します。2>&1は標準エラーが現在の標準出力の宛先を指すようにします。

ls absent-14.txt > all.txt 2>&1
cat all.txt

リダイレクトは左から右に処理されるため、2>&1 > all.txtで順序を逆にすると同じ結果にはなりません。逆にした場合、エラーは既存の標準出力の宛先である画面に残る可能性があります。

パイプで二つのコマンドを接続する

パイプ | は、左側のコマンドの標準出力を右側のコマンドの標準入力に送ります。次の例は、beta を含む行を検索し、それらの行数をカウントします。

grep 'beta' source.txt | wc -l

この実習データでは 1 が出力されます。左側のコマンドの標準エラーは、通常のパイプには含まれません。また Bash の基本的なパイプライン終了ステータスは最後のコマンドの状態なので、grep で一致する項目がなくても、wc -l が正常に 0 を出力すれば、全体の状態は成功となる場合があります。複数段階の失敗の有無が重要な場合は、Bash の pipefail 設定など、別の確認方法を検討する必要があります。

リダイレクションはファイルとコマンドの通路を切り替え、パイプはコマンドとコマンドを接続します。結果が期待と異なる場合は、各コマンドを単独で実行し、標準出力とエラーのどちらから値が出力されているかをまず確認してください。

公式ドキュメント

GNU Bash リダイレクションの文書は <・>・2> と処理順序を、GNU Bash パイプラインの文書はパイプ接続と終了状態を説明します。