setで失敗を扱う
自動実行するスクリプトでは、途中のコマンドが失敗したのに最後だけ成功してしまう状態を避けたいことがあります。代表的な設定を確認します。
| 設定 | 意味 | 注意点 |
|---|---|---|
set -e | 失敗したコマンドの後で終了 | ifの条件など、失敗が想定内の処理もある |
set -u | 未定義変数をエラーにする | 任意の変数には初期値やデフォルト値を用意する |
set -o pipefail | パイプ途中の失敗も検出 | 検索結果が空になる処理の終了コードを確認する |
#!/usr/bin/env bash
set -Eeuo pipefail
printf 'チェックを開始します。\n'チェックを開始します。便利な設定ですが、意味を理解せずに追加すると、検索結果がない場合など正しい分岐まで失敗扱いにすることがあります。小さな例で挙動を確かめてから使います。
入力値と対象を検証する
ユーザーが渡したパスやオプションは、存在、種類、読み書き権限を確認します。バックアップ元と保存先が同じでないかも、実務では確認したい条件です。
source_dir="${1:-}"
if [[ -z "$source_dir" || ! -d "$source_dir" ]]; then
printf 'ディレクトリを指定してください。\n' >&2
printf '使い方: %s ディレクトリ\n' "$0" >&2
exit 2
fi
printf '対象: %s\n' "$source_dir"bash check.sh data対象: data${1:-}は1番目の引数がなければ空文字にする書き方です。未定義変数をエラーにするset -uと組み合わせるときに役立ちます。
trapで後処理を登録する
一時ファイルを作った場合、成功時だけでなく途中で失敗した場合も削除したいことがあります。trapに終了時の処理を登録します。
temp_file=$(mktemp)
cleanup() {
rm -f "$temp_file"
}
trap cleanup EXIT
printf 'temporary data\n' > "$temp_file"
cat "$temp_file"temporary datamktempは一時ファイルを作り、そのパスを返します。trap cleanup EXITを登録したあとなら、処理が終わるときにcleanupが呼ばれます。削除対象は固定値にせず、作成したファイルだけを変数で指定します。
ログと標準エラーを分ける
定期実行では、いつ何をしたかを後から確認できるようにログを残します。通常の結果とエラーを分け、日時も一緒に記録します。
log_file='script.log'
log() {
printf '[%s] %s\n' "$(date '+%F %T')" "$*" | tee -a "$log_file"
}
fail() {
printf '[%s] ERROR: %s\n' "$(date '+%F %T')" "$*" >&2
exit 1
}
log '処理を開始しました。'
[[ -d data ]] || fail 'dataがありません。'[2026-10-09 10:00:00] 処理を開始しました。ログへ個人情報や秘密情報をそのまま書かないようにします。パスワードやアクセストークンは、コマンドライン引数やログへ出さない設計にします。
ShellCheckで静的に確認する
ShellCheckは、シェルスクリプトのよくある問題を静的に指摘するツールです。未引用の変数や、意図しない代入などを実行前に発見できます。
#!/usr/bin/env bash
source="source file.txt"
target="backup.txt"
cp $source $targetshellcheck backup.shIn backup.sh line 4:
cp $source $target
^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.
^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.指摘は必ず理由を読んでから直します。すべての警告を機械的に無視するのではなく、引用符を付けることで何が安全になるのかを理解します。
定期実行の前に確認する
cronなどで定期実行すると、対話シェルと環境変数や現在地が異なります。相対パスに頼らず、実行ファイル内で作業場所やログの場所を明示します。
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
log_file="$script_dir/cron.log"
printf '[%s] started\n' "$(date '+%F %T')" >> "$log_file"
cat "$log_file"[2026-10-09 23:04:20] started登録前に、手動で何度も実行し、入力がない環境でも動くか、終了ステータスが適切か、ログだけで原因を追えるかを確認します。実行間隔やタイムゾーンも運用環境で確認します。
練習:安全な確認スクリプト
引数で受け取ったディレクトリについて、存在確認、ファイル数表示、ログ保存を行うスクリプトを作ってください。
#!/usr/bin/env bash
set -u
target="${1:-}"
if [[ -z "$target" || ! -d "$target" ]]; then
printf '使い方: %s ディレクトリ\n' "$0" >&2
exit 2
fi
count=$(find "$target" -type f | wc -l)
printf '[%s] %s のファイル数: %s\n' \
"$(date '+%F %T')" "$target" "$count"bash inspect.sh data
[2026-10-09 10:10:00] data のファイル数: 2次は総合練習問題で、これまでの内容を組み合わせます。