Bash Strict Mode: set -euo pipefailの解説

set -euo pipefailでbash strict modeをマスター。各フラグの機能、一般的な落とし穴、予期される失敗の適切な処理方法を解説します。

Script Setup

詳細な説明

Bash Strict Mode

スクリプトの先頭近くにset -euo pipefailを追加すると、ほとんどの一般的なスクリプトバグをダメージが発生する前にキャッチする3つの安全設定が有効になります。

3つのフラグ

#!/usr/bin/env bash
set -euo pipefail

set -e(errexit): コマンドがゼロ以外のステータスを返した場合、即座に終了します。これがないと、スクリプトは失敗後も続行し、古いまたは欠落したデータで操作する可能性があります。

set -e
cd /nonexistent/path  # スクリプトはここで終了
rm -rf *              # 実行されない

set -u(nounset): 未設定の変数をエラーとして扱います。これがないと、$TYPOは暗黙的に空文字列に展開されます。

set -u
echo "$UNSET_VAR"  # エラー: UNSET_VAR: unbound variable

set -o pipefail: パイプラインで最初に失敗したコマンドの終了ステータスを返します。これがないと、最後のコマンドの終了ステータスのみが使用されます。

set -o pipefail
false | true  # パイプラインが失敗(falseがゼロ以外を返した)
echo "この行はset -eでは到達しない"

予期される失敗の処理

コマンドの失敗が許容される場合、以下のパターンを使用します:

# パターン1: || true
grep "pattern" file.txt || true  # grepが何も見つからなくてもOK

# パターン2: if文
if grep -q "pattern" file.txt; then
  echo "Found"
fi

# パターン3: 一時的に無効化
set +e
risky_command
result=$?
set -e

一般的な落とし穴

localでのコマンド置換: localキーワードがコマンド置換の終了ステータスをマスクします:

# 悪い例: localがエラーをマスク
local result=$(failing_command)  # エラーが発生しない!

# 良い例: 宣言と代入を分離
local result
result=$(failing_command)  # エラーが適切に発生

完全なテンプレート

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

# スクリプトをここに記述

IFS行はワードスプリッティングを改行とタブに制限し、追加の安全層を提供します。

ユースケース

特定の理由がない限り、すべてのbashスクリプトはstrict modeで開始すべきです。デプロイスクリプト、データ処理パイプライン、システム管理タスク、およびサイレントな失敗がデータ損失を引き起こす可能性のあるスクリプトで特に重要です。

試してみる — Shell Script Linter

フルツールを開く