[META:VERSION] 2024-05-22-SRE-BASH [META:ROLE] Senior SRE / DevOps Engineer [META:FOCUS] Robustness, Error Handling, Idempotency, Clean Code [META:LOG] Shell automation design pattern using Bash fail-safes and traps.
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
堅牢なシェルスクリプト設計:set -euo pipefailとtrapによる副作用の最小化
【導入と前提】 APIから構成データを取得し、一時的な加工を経てシステムへ適用する処理を、エラー発生時のゴミを残さず安全に自動化します。
OS: GNU/Linux (Bash 4.4+)
Tools: curl, jq, systemd
【処理フローと設計】
graph TD
A["スクリプト開始"] --> B["シェルオプション設定/trap登録"]
B --> C["一時ディレクトリ作成"]
C --> D["外部APIからJSON取得: curl"]
D --> E["データ抽出/バリデーション: jq"]
E --> F["メイン処理の実行"]
F --> G["正常終了"]
G --> H["trapによる一時ファイル削除"]
D -- エラー時 --> H
E -- 異常値検出 --> H
F -- 処理失敗 --> H
H --> I["スクリプト終了"]
エラーが発生した際、どのフェーズであってもtrapが介在し、作成された一時ファイルや中間データを確実に破棄してシステムをクリーンな状態に保ちます。
【実装:堅牢な自動化スクリプト】
#!/usr/bin/env bash
# -e: エラー時に即終了, -u: 未定義変数でエラー, -o pipefail: パイプ途中のエラーを拾う
set -euo pipefail
# ログ出力用関数
log() { echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] $*"; }
# 終了時のクリーンアップ処理(正常・異常を問わず実行)
cleanup() {
local exit_status=$?
if [ -d "${TMP_DIR:-}" ]; then
rm -rf "$TMP_DIR"
log "INFO: Temporary directory deleted."
fi
log "INFO: Script finished with status $exit_status"
exit "$exit_status"
}
# EXITシグナルを捕捉してcleanupを実行
trap cleanup EXIT
# 初期設定
API_URL="https://api.example.com/v1/config"
TMP_DIR=$(mktemp -d)
CONFIG_FILE="$TMP_DIR/config.json"
log "INFO: Starting process..."
# curlによるデータ取得
# -s: 進捗非表示, -S: エラー時のみ表示, -f: HTTPエラー(4xx/5xx)で失敗扱い, -L: リダイレクト追従
curl -sSfL "$API_URL" -o "$CONFIG_FILE" || {
log "ERROR: Failed to fetch configuration from $API_URL"
exit 1
}
# jqによるパースとバリデーション
# -r: raw output, -e: 結果がnull/falseなら終了コード1
TARGET_VERSION=$(jq -re '.version' "$CONFIG_FILE")
log "INFO: Target configuration version: $TARGET_VERSION"
# メインの処理(例:設定の反映)
# ... ここに具体的なロジックを記述 ...
log "SUCCESS: All tasks completed successfully."
補足:systemd タイマー設定例
定期実行が必要な場合は、以下のユニットファイルで管理することでログ管理をjournaldに集約できます。
# /etc/systemd/system/config-sync.service [Unit] Description=Robust Config Sync Service [Service] Type=oneshot ExecStart=/usr/local/bin/config-sync.sh User=app-user Group=app-user
【検証と運用】
正常系の確認:
bash -n config-sync.sh # 構文チェック ./config-sync.sh # 実行 echo $? # 終了コード0を確認
異常系の確認: APIのURLを無効なものに変更して実行し、
TMP_DIRが残っていないこと、およびログにエラーが記録されていることを確認します。ログ確認:
journalctl -u config-sync.service
【トラブルシューティングと落とし穴】
pipefailの罠:
grepでマッチしない場合に終了コード1が返り、スクリプトが停止することがあります。必要に応じてgrep ... || trueで許容するか検討してください。一時ファイルの肥大化:
mktempを使用する際、ディスク容量不足(/tmpのフル)に注意してください。環境変数の漏洩: APIキーなどの機密情報を扱う際は、
exportせず、必要なコマンドにのみ渡すか、jqの--argなどで安全に処理してください。
【まとめ】
フェイルファースト:
set -eにより、予期せぬ挙動を放置せず即座に停止させる。リソースの自己完結:
trapを使い、異常時でも一時ファイルやロックファイルを確実に回収する。ステータスの可視化: パイプラインの各段階で
jqやcurl -fを活用し、論理的なエラーを終了コードに変換する。

