exit / return
| 対応: | POSIX(sh互換) |
|---|
『シェルスクリプト』では、処理の終了を伝える手段として exit と return の2つのコマンドがあります。exit n はスクリプト(またはサブシェル)全体を終了させ、n を終了ステータスとして親プロセスに返します。return n は関数の中だけで使い、その関数から復帰するときに終了ステータスを設定します。どちらも 0 が成功、1〜255 が失敗を表すのが慣習です。また set -e を使うと終了ステータスが 0 以外のコマンドが実行された時点でスクリプトを即座に終了させられるため、エラーの見落としを防ぐのに役立ちます。
exit と return の比較
| コマンド | 使える場所 | 終了する対象 | 説明 |
|---|---|---|---|
exit n | スクリプトのどこでも | スクリプト全体(またはサブシェル) | スクリプトを終了してステータス n を親プロセスに返します。省略すると直前のコマンドの終了ステータスが使われます。 |
return n | 関数の中のみ | 現在の関数 | 関数から復帰してステータス n を呼び出し元に返します。関数の外で使うと source 実行中のスクリプトを終了させます。 |
終了ステータスの慣習
終了ステータスは 0〜255 の整数です。0 が成功を意味し、1〜255 はエラーや異常終了を意味します。直前のコマンドの終了ステータスは特殊変数 $? で確認できます。
| 終了ステータス | 意味 | 説明 |
|---|---|---|
0 | 成功 | 処理が正常に完了したことを表します。if 文の条件が「真」と評価されます。 |
1 | 一般的なエラー | 多くのコマンドがエラー時に返すステータスです。明示的な意味が決まっていない失敗に使います。 |
2 | シェルの使い方のエラー | 不正なオプション・引数不足など、コマンドの使い方が誤っている場合に返します。 |
126 | 実行権限なし | ファイルは存在するが実行権限がない場合にシェルが設定します。 |
127 | コマンドが見つからない | 指定したコマンドが PATH 上に存在しない場合にシェルが設定します。 |
128+n | シグナルによる終了 | シグナル番号 n で強制終了した場合に設定されます(例: SIGTERM=15 なら 143)。 |
# -----------------------------------------------
# $? で終了ステータスを確認します
# -----------------------------------------------
# 成功するコマンドの後に確認します
ls /tmp
echo "ls の終了ステータス: $?" # 0
# 失敗するコマンドの後に確認します
ls /no_such_directory 2>/dev/null
echo "ls の終了ステータス: $?" # 0 以外(通常 2)
# $? は直前のコマンドのステータスを上書きするため
# すぐ参照するか変数に保存します
some_command
status=$? # ← すぐ保存します
echo "ステータス: ${status}"
set -e(エラー時即時終了)
set -e をスクリプトの先頭付近に書くと、終了ステータスが 0 以外のコマンドが実行された時点でスクリプト全体を即座に終了させます。エラーを見落としたまま処理を続けてしまう事故を防げます。ただし if 文の条件式・while / until の条件式・|| や && でつないだコマンドは失敗しても終了しません。
| オプション | 説明 |
|---|---|
set -e | 終了ステータスが 0 以外のコマンドが実行された時点でスクリプトを終了します。 |
set -u | 未定義の変数を参照するとエラーにします。set -e と組み合わせてよく使います。 |
set -o pipefail | パイプライン内のいずれかのコマンドが失敗した場合、パイプライン全体の終了ステータスを失敗にします。 |
set -euo pipefail | 上記3つをまとめて有効にします。堅牢なスクリプトでよく使われる定番の組み合わせです。 |
command || true | set -e 有効時に、失敗しても終了させたくないコマンドに付けます。 |
# ----------------------------------------------- # set -e の動作確認 # ----------------------------------------------- set -e echo "処理 1: 開始" # 存在しないファイルの削除は失敗します(終了ステータス 1) # set -e があるためここでスクリプトが終了します rm /no_such_file echo "処理 2: ここには到達しません" # 実行されません # ----------------------------------------------- # 失敗を許容したい場合は || true を使います # ----------------------------------------------- set -e echo "処理 1: 開始" # || true を付けると失敗してもスクリプトを続けられます rm /no_such_file || true echo "処理 2: ここに到達します" # 実行されます
exit と return の使い方
# -----------------------------------------------
# exit n: スクリプト全体を終了します
# -----------------------------------------------
# 引数チェックに失敗したらエラーメッセージを表示して終了します
if [ "$#" -lt 1 ]; then
echo "使い方: $0 <名前>" >&2 # エラーは標準エラー出力へ
exit 1 # 異常終了(ステータス 1)
fi
echo "こんにちは、$1 さん"
exit 0 # 正常終了(省略も可)
# -----------------------------------------------
# return n: 関数から復帰します
# -----------------------------------------------
# 認証チェック関数: 成功なら 0、失敗なら 1 を返します
check_auth() {
local user="$1"
local pass="$2"
if [ -z "${user}" ] || [ -z "${pass}" ]; then
echo "ユーザー名またはパスワードが空です" >&2
return 1 # 失敗を返します
fi
# 認証処理(ここでは簡易チェック)
if [ "${user}" = "admin" ] && [ "${pass}" = "secret" ]; then
return 0 # 認証成功
else
return 1 # 認証失敗
fi
}
# $? で return の値を確認します
check_auth "admin" "secret"
if [ "$?" -eq 0 ]; then
echo "ログイン成功"
else
echo "ログイン失敗"
fi
サンプルコード
sg_exit_basic.sh
#!/bin/bash
# -----------------------------------------------
# Steins;Gate のキャラクターで
# exit と終了ステータスの基本を確認します
# -----------------------------------------------
# -----------------------------------------------
# ラボメン認証関数
# 引数: $1=ラボメンナンバー(整数)
# return: 0=認証成功, 1=番号なし, 2=番号が範囲外
# -----------------------------------------------
check_labmem() {
local number="$1"
# 引数が空の場合は失敗を返します
if [ -z "${number}" ]; then
echo "エラー: ラボメンナンバーを指定してください" >&2
return 1
fi
# 番号が 1〜11 の範囲内かチェックします
if [ "${number}" -lt 1 ] || [ "${number}" -gt 11 ]; then
echo "エラー: ラボメンナンバーは 1〜11 の範囲で指定してください" >&2
return 2
fi
return 0
}
# -----------------------------------------------
# ラボメン名前解決関数
# 引数: $1=ラボメンナンバー
# echo: 対応するキャラクター名を出力します
# -----------------------------------------------
get_labmem_name() {
local number="$1"
case "${number}" in
1) echo "岡部倫太郎" ;;
2) echo "椎名まゆり" ;;
3) echo "橋田至" ;;
4) echo "桐生萌郁" ;;
5) echo "漆原るか" ;;
6) echo "フェイリス・ニャンニャン" ;;
7) echo "阿万音鈴羽" ;;
8) echo "牧瀬紅莉栖" ;;
*) echo "不明" ;;
esac
}
# -----------------------------------------------
# スクリプトの引数チェック(exit でスクリプト自体を終了します)
# -----------------------------------------------
if [ "$#" -ne 1 ]; then
echo "使い方: $0 <ラボメンナンバー>" >&2
echo "例: $0 1" >&2
exit 1 # 引数エラーで終了します
fi
INPUT="$1"
# -----------------------------------------------
# 認証チェック
# -----------------------------------------------
check_labmem "${INPUT}"
STATUS=$?
if [ "${STATUS}" -eq 0 ]; then
# 認証成功: 名前を取得して表示します
NAME=$(get_labmem_name "${INPUT}")
echo "認証成功: ラボメンNo.${INPUT} → ${NAME}"
echo "ようこそ、未来ガジェット研究所へ。"
exit 0 # 正常終了
elif [ "${STATUS}" -eq 2 ]; then
echo "番号が範囲外です。El Psy Kongroo." >&2
exit 2 # 範囲外エラーで終了します
else
echo "認証失敗。侵入者警告。" >&2
exit 1 # 一般エラーで終了します
fi
$ chmod +x sg_exit_basic.sh # 引数なしで実行します(exit 1 で終了) $ ./sg_exit_basic.sh 使い方: ./sg_exit_basic.sh <ラボメンナンバー> 例: ./sg_exit_basic.sh 1 $ echo $? 1 # ラボメンNo.1 で実行します(exit 0 で終了) $ ./sg_exit_basic.sh 1 認証成功: ラボメンNo.1 → 岡部倫太郎 ようこそ、未来ガジェット研究所へ。 $ echo $? 0 # ラボメンNo.8 で実行します $ ./sg_exit_basic.sh 8 認証成功: ラボメンNo.8 → 牧瀬紅莉栖 ようこそ、未来ガジェット研究所へ。 $ echo $? 0 # 範囲外の番号で実行します(exit 2 で終了) $ ./sg_exit_basic.sh 99 エラー: ラボメンナンバーは 1〜11 の範囲で指定してください 番号が範囲外です。El Psy Kongroo. $ echo $? 2
sg_set_e.sh
#!/bin/bash
# -----------------------------------------------
# Steins;Gate のキャラクターで
# set -euo pipefail の動作を確認します
# -----------------------------------------------
# set -euo pipefail を先頭で有効にします
# -e: コマンドが失敗したら即時終了します
# -u: 未定義変数の参照をエラーにします
# -o pipefail: パイプライン途中の失敗も検知します
set -euo pipefail
# -----------------------------------------------
# ヘルパー関数: エラーメッセージを出力して終了します
# -----------------------------------------------
die() {
# $1 にメッセージ、$2 に終了ステータス(省略時は 1)を指定します
local message="$1"
local code="${2:-1}"
echo "[エラー] ${message}" >&2
exit "${code}"
}
# -----------------------------------------------
# ファイル存在チェック関数
# 引数: $1=ファイルパス
# return: 0=存在する, 1=存在しない
# -----------------------------------------------
require_file() {
local filepath="$1"
if [ ! -f "${filepath}" ]; then
return 1 # ファイルが存在しません
fi
return 0
}
# -----------------------------------------------
# タイムリープログ処理関数
# 引数: $1=ラボメン名, $2=世界線変動率
# -----------------------------------------------
process_leap_log() {
local member="$1"
local divergence="$2"
# 世界線変動率が空でないか確認します(-u オプションで未定義変数も検知します)
if [ -z "${divergence}" ]; then
echo " 警告: ${member} の世界線変動率が未設定です" >&2
return 1 # 異常を返します(set -e のスコープ外なので終了しません)
fi
echo " ${member}: 世界線 ${divergence}% に移動を記録しました"
return 0
}
# -----------------------------------------------
# メイン処理
# -----------------------------------------------
LOG_DIR="/tmp/steinsgate_logs"
LOG_FILE="${LOG_DIR}/leap_record.txt"
echo "=== タイムリープ記録システム 起動 ==="
echo ""
# ディレクトリを作成します(失敗すると set -e でスクリプト終了)
mkdir -p "${LOG_DIR}"
echo "ログディレクトリを作成しました: ${LOG_DIR}"
# ラボメンのタイムリープ記録を処理します
echo ""
echo "--- タイムリープ記録の処理 ---"
# 各ラボメンのデータを処理します
# || true を付けると関数が return 1 でも set -e に反応しません
process_leap_log "岡部倫太郎" "1.048596" || true
process_leap_log "牧瀬紅莉栖" "1.130205" || true
process_leap_log "椎名まゆり" "0.000000" || true
process_leap_log "阿万音鈴羽" "1.048596" || true
process_leap_log "フェイリス・ニャンニャン" "1.382733" || true
# ログファイルに書き出します(失敗すると set -e でスクリプト終了)
{
echo "# タイムリープ記録ファイル"
echo "# 生成日時: $(date '+%Y-%m-%d %H:%M:%S')"
echo "岡部倫太郎,1.048596"
echo "牧瀬紅莉栖,1.130205"
echo "椎名まゆり,0.000000"
echo "阿万音鈴羽,1.048596"
echo "フェイリス・ニャンニャン,1.382733"
} > "${LOG_FILE}"
echo ""
echo "ログファイルに書き出しました: ${LOG_FILE}"
# ファイルが生成されたか確認します
require_file "${LOG_FILE}" || die "ログファイルの生成に失敗しました" 1
echo ""
echo "=== 処理完了 ==="
echo "終了ステータス: 0(成功)"
exit 0
$ chmod +x sg_set_e.sh $ ./sg_set_e.sh === タイムリープ記録システム 起動 === ログディレクトリを作成しました: /tmp/steinsgate_logs --- タイムリープ記録の処理 --- 岡部倫太郎: 世界線 1.048596% に移動を記録しました 牧瀬紅莉栖: 世界線 1.130205% に移動を記録しました 椎名まゆり: 世界線 0.000000% に移動を記録しました 阿万音鈴羽: 世界線 1.048596% に移動を記録しました フェイリス・ニャンニャン: 世界線 1.382733% に移動を記録しました ログファイルに書き出しました: /tmp/steinsgate_logs/leap_record.txt === 処理完了 === 終了ステータス: 0(成功) $ echo $? 0
概要
『シェルスクリプト』における終了ステータスは、コマンドや関数・スクリプトが成功したか失敗したかを数値(0〜255)で伝える仕組みです。exit n はスクリプト全体(またはサブシェル)を終了させ、return n は関数から復帰するときに使います。どちらも 0 が成功、1〜255 が失敗の慣習で、直前の終了ステータスは $? で確認できます。set -e を有効にすると失敗したコマンドが即座にスクリプトを終了させるため、エラーの見落としを防ぐ堅牢なスクリプトを書くのに役立ちます。set -u(未定義変数の参照をエラー化)・set -o pipefail(パイプライン途中の失敗を検知)と組み合わせた set -euo pipefail は本番スクリプトの定番設定です。関数の詳細については function(関数定義・引数・スコープ)、終了ステータスを条件分岐に使う方法は if 文 も合わせて参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。