このレッスンで学ぶこと
堅牢なシェルスクリプトを作成するには、適切なエラーハンドリングとデバッグ技術が不可欠です。このレッスンでは:
- 終了ステータスの理解と活用
- エラートラップとシグナル処理
- デバッグモードの使い方
- ログ出力とエラーメッセージ
終了ステータスの基本
終了ステータスの確認
#!/bin/bash
# コマンドの実行と終了ステータスの確認
ls /etc/passwd
echo "終了ステータス: $?"
ls /nonexistent/file
echo "終了ステータス: $?"
# 条件分岐での使用
if grep -q "root" /etc/passwd; then
echo "rootユーザーが見つかりました"
else
echo "rootユーザーが見つかりません"
fi
CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$
█
ファイルツリー
/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log
カスタム終了ステータス
#!/bin/bash
# 関数での終了ステータス
validate_age() {
local age=$1
if [ -z "$age" ]; then
echo "エラー: 年齢が指定されていません"
return 1
fi
if ! [[ "$age" =~ ^[0-9]+$ ]]; then
echo "エラー: 数値ではありません"
return 2
fi
if [ "$age" -lt 0 ] || [ "$age" -gt 120 ]; then
echo "エラー: 有効な範囲外です"
return 3
fi
echo "年齢 $age は有効です"
return 0
}
# スクリプト全体の終了
if ! validate_age "$1"; then
exit $?
fi
エラーハンドリングのベストプラクティス
set オプションの活用
#!/bin/bash
# エラー時に即座に終了
set -e
# 未定義変数の使用をエラーに
set -u
# パイプラインのエラーを検出
set -o pipefail
# すべてを一度に設定
set -euo pipefail
# 実行例
echo "スクリプト開始"
ls /nonexistent/file # ここでスクリプトが終了
echo "この行は実行されません"
CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$
█
ファイルツリー
/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log
エラートラップ
#!/bin/bash
# エラー発生時の処理を定義
error_handler() {
local line_no=$1
echo "エラーが発生しました (行: $line_no)"
echo "スタックトレース:"
local i=0
while caller $i; do
((i++))
done
exit 1
}
# ERRシグナルをトラップ
trap 'error_handler $LINENO' ERR
# クリーンアップ処理
cleanup() {
echo "クリーンアップ処理を実行..."
rm -f /tmp/tempfile.$$
}
# 終了時の処理
trap cleanup EXIT
# メイン処理
echo "処理を開始します"
touch /tmp/tempfile.$$
ls /nonexistent/file # エラーが発生
echo "この行は実行されません"
デバッグ技術
デバッグモード
#!/bin/bash
# デバッグモードを有効化
set -x # 実行するコマンドを表示
# または
#!/bin/bash -x
# 部分的なデバッグ
set +x # デバッグモードを無効化
echo "通常の実行"
set -x # デバッグモードを有効化
echo "デバッグ対象の処理"
set +x # デバッグモードを無効化
CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$
█
ファイルツリー
/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log
ログ出力関数
#!/bin/bash
# ログレベルの定義
readonly LOG_LEVEL_ERROR=1
readonly LOG_LEVEL_WARN=2
readonly LOG_LEVEL_INFO=3
readonly LOG_LEVEL_DEBUG=4
# 現在のログレベル
LOG_LEVEL=${LOG_LEVEL:-$LOG_LEVEL_INFO}
# ログ出力関数
log() {
local level=$1
shift
local message="$@"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case $level in
$LOG_LEVEL_ERROR)
[ $LOG_LEVEL -ge $LOG_LEVEL_ERROR ] && echo "[$timestamp] ERROR: $message" >&2
;;
$LOG_LEVEL_WARN)
[ $LOG_LEVEL -ge $LOG_LEVEL_WARN ] && echo "[$timestamp] WARN: $message" >&2
;;
$LOG_LEVEL_INFO)
[ $LOG_LEVEL -ge $LOG_LEVEL_INFO ] && echo "[$timestamp] INFO: $message"
;;
$LOG_LEVEL_DEBUG)
[ $LOG_LEVEL -ge $LOG_LEVEL_DEBUG ] && echo "[$timestamp] DEBUG: $message"
;;
esac
}
# 使用例
log $LOG_LEVEL_INFO "スクリプトを開始しました"
log $LOG_LEVEL_DEBUG "変数の値: VAR=$VAR"
log $LOG_LEVEL_ERROR "ファイルが見つかりません"
実践的なエラーハンドリング
CommandAcademy Terminal
Welcome to CommandAcademy Terminal!
Type "help" to see available commands.
user@cmdac:~$
█
ファイルツリー
/
etc
hosts35B
passwd76B
home
user
tmp
usr
bin
share
var
log
デバッグのヒントとコツ
変数の内容を確認
#!/bin/bash
# 変数の値を表示
debug_var() {
local var_name=$1
local var_value=${!var_name}
echo "[DEBUG] $var_name='$var_value'" >&2
}
# 使用例
MY_VAR="test value"
debug_var MY_VAR
# 配列の内容を表示
debug_array() {
local array_name=$1
local array_ref="${array_name}[@]"
echo "[DEBUG] $array_name=(${!array_ref})" >&2
}
MY_ARRAY=(one two three)
debug_array MY_ARRAY
アサーション
#!/bin/bash
# アサーション関数
assert() {
local condition="$1"
local message="${2:-Assertion failed}"
if ! eval "$condition"; then
echo "ASSERTION ERROR: $message" >&2
echo "Condition: $condition" >&2
caller 0 >&2
exit 1
fi
}
# 使用例
value=10
assert "[ $value -gt 0 ]" "値は正の数である必要があります"
assert "[ -f /etc/passwd ]" "/etc/passwdファイルが存在する必要があります"
まとめ
このレッスンでは、シェルスクリプトのエラーハンドリングとデバッグについて学びました:
- 終了ステータス: コマンドの成功/失敗を判定
- エラーハンドリング: set オプション、トラップ、エラー処理
- デバッグ技術: デバッグモード、ログ出力、変数確認
- 堅牢な実装: 入力検証、クリーンアップ、エラーメッセージ
これらの技術により、信頼性の高いプロダクションレベルのスクリプトを作成できます。
次のステップ
次のレッスンでは、これまでに学んだ知識を活用して、実践的なバックアップスクリプトを作成します。