pipe とは何か? シェルでコマンドを接続する
pipe は、| 文字で書かれ、あるコマンドの標準出力を次のコマンドの標準入力に接続し、ツールを連鎖させることを可能にします。
pipe はシェルで最も強力なアイデアの 1 つです。それぞれ 1 つのことを行う小さなプログラムを、一方の出力が次の入力になるように接続します。CI スクリプトは pipe を常に使いますが、pipe には罠も隠れています。より厳格な挙動を選択しない限り、pipeline 途中の失敗が見過ごされる可能性があるのです。
pipe が行うこと
| 演算子は、左側のコマンドの stdout を取り、それを右側のコマンドの stdin として供給します。cat log.txt | grep ERROR | wc -l は、3 つのツールを連鎖させてエラー行を数えます。
pipe が有用な理由
pipe を使うと、一時ファイルなしで単純なコマンドを組み合わせて複雑な挙動を構成できます。各プログラムは焦点を絞ったままで、コマンドラインでそれらを構成要素のように組み立てます。
終了コードの罠
- デフォルトでは pipeline の終了コードは最後のコマンドのものだけ。
- 前のコマンドが失敗しても最後が成功すれば、pipeline は問題なく見える。
- これは CI ステップ内の本物の失敗を隠す可能性がある。
pipefail で修正する
set -o pipefail を実行するとルールが変わります。pipeline はその中のいずれかのコマンドが失敗すると失敗します。set -e と組み合わせると、壊れたステージが見過ごされるのではなく、実際に job を停止させます。
CI における pipe
典型的な CI のバグは generate | tee output.txt で、generate がクラッシュしても tee が成功するため、ステップが空の出力で pass します。set -o pipefail を追加すると、まさにこれを捉えます。だからこそ set -euo pipefail に含まれるのです。
managed runner での信頼できる pipeline
Latchkey runner では、ステップの先頭で pipefail を有効にすると、pipe のどこかでの失敗が job を失敗させます。それは、静かで追跡しにくいバグを明確で早期の失敗に変えます。
重要なポイント
- pipe は、あるコマンドの stdout を次のコマンドの stdin に接続します。
- デフォルトでは最後のコマンドの終了コードだけが数えられ、pipe 途中の失敗を隠します。
set -o pipefailは、失敗したコマンドがあれば pipeline 全体を失敗させます。