本文へスキップ
BecomeCoder

シェルスクリプトコース · 第7章 安全に書く · レッスン29

set -e / set -u ― 失敗したら止める

ブラウザで完結

導入

シェルスクリプトの既定の動きは「1行失敗しても、次の行を実行する」です。バックアップに失敗したのに、その次の「古いファイルを削除」だけが成功する——考えるだけで恐ろしい挙動です。これを変えるのが set です。

説明

スクリプトの冒頭に書く「おまじない」の正体を理解しましょう。

#!/bin/bash
set -e
set -u

echo "1: 開始します"

# 失敗するコマンド(存在しないファイル)
cat noexist.txt

echo "2: ここは実行されません"
指定意味防げる事故
set -eコマンドが失敗したらそこで終了失敗を無視して次に進む
set -u未定義の変数を使ったらエラーrm -rf $TYPO/rm -rf / になる
set -o pipefailパイプの途中の失敗も検知するgrep x file | wc -l の失敗を見逃す
set -x実行した行を表示するデバッグ用(レッスン33)

3つまとめて set -euo pipefail と書くのが、現代のシェルスクリプトの定型句です。

flowchart TD
    A["cat noexist.txt が失敗"] --> B{"set -e は?"}
    B -->|"なし(既定)"| C["次の行へ進む<br/>(危険)"]
    B -->|"あり"| D["その場でスクリプト終了<br/>(安全)"]

set -u の効果も見ておきましょう。変数名を打ち間違えたとき、既定では空文字として黙って動いてしまうのが、シェルの怖いところです。

set -u
echo "対象: $TAGET"    # TARGET の打ち間違い → エラーで止まる

注意点として、set -e は「失敗してもよい」場面と相性が悪いことがあります。grep が何も見つけられないと終了ステータス 1 を返すので、そこで止まってしまうのです。意図的に無視したいときは || true を付けます。

count=$(grep ERROR logs/app.log | wc -l || true)

やってみよう

スクリプトを実行して、2: ここは実行されません が出ないことを確かめましょう。次に set -e の行をコメントアウト(先頭に #)して実行すると、エラーのあとも 2: が表示されます。この差が事故と無事故の分かれ目です。

演習

set -e を有効にしたまま、失敗するコマンドの後ろに || true を付けて、最後まで到達しました を表示させてください。

ヒント1を見る

cat noexist.txt 2> /dev/null || true のように書くと、失敗しても止まりません。

ヒント2を見る

その次の行に echo "最後まで到達しました"

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

シェルスクリプト(シミュレート)

スクリプトを書くエディタと、それを動かす仮想シェルを読み込みます(本物のbashではなく、動きを再現した学習用の環境です)。
スクロールして表示された時点でも自動で読み込まれます。