シェルスクリプトの前提条件チェック設計|実行前にコマンド・ファイル・権限・ディスク容量を一括検証する方法

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > シェルスクリプト > シェルスクリプトの前提条件チェック設計|実行前にコマンド・ファイル・権限・ディスク容量を一括検証する方法
「バックアップスクリプトを動かしたら rsync が入っていなかった」「ディスク容量が足りなくて途中終了して、アーカイブファイルが壊れていた」——こうした実行してから発覚する問題は、メイン処理に入る前の一括チェックで防げます。
シェルスクリプトで信頼性を高める第一歩は、preflight(プリフライト)チェック の設計です。必要なコマンド・ファイル・権限・ディスク容量が揃っているかをスクリプトの冒頭で確認し、条件が不足していれば処理を始める前に明確なエラーメッセージを出して終了する。

この記事では、コマンドの存在確認・ファイルや権限の検証・ディスク空き容量のチェックを再利用可能な関数にまとめる設計パターンを解説します。実際のバックアップスクリプトへの組み込み例も示します。
動作確認環境: Rocky Linux 9.4 / Ubuntu 24.04 LTS(bash 5.2)

この記事のポイント

・command -v でコマンドの存在を確認し、なければ即 exit する
・ファイル・ディレクトリ・権限は -f/-d/-r/-w テストで事前検証する
・ディスク空き容量は df -k と算術展開で数値化して閾値比較する
・require_cmd / require_dir 関数に集約するとどのスクリプトにも使い回せる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜ前提条件チェックが必要なのか

スクリプトが途中で失敗すると、2つの問題が起きます。

1つ目は「中途半端な状態が残る」こと。バックアップスクリプトが途中で落ちると、不完全なアーカイブが出力先に残ります。世代管理している場合は「壊れたバックアップが正常ファイルとして記録される」事態になります。

2つ目は「エラーメッセージが不親切」なこと。コマンドが見つからない場合のデフォルトエラーは rsync: command not found ですが、インストール方法まで伝えてはくれません。スクリプトが自分でチェックして「必要なコマンドがありません: rsync。yum install rsync でインストールしてください。」と出力すれば、対処が速くなります。

preflight チェックは「守りの設計」です。メイン処理を書く前に動作の前提条件を明文化する作業でもあります。

コマンドの存在確認(command -v)

コマンドが存在するかどうかを確認するには command -v を使います。which はシェルの組み込みコマンドを検出できない場合があり、エイリアスも見落とすことがあるため、command -v のほうが信頼性が高いです。

1. 1コマンドをチェックする基本形

#!/bin/bash set -euo pipefail # コマンドが存在しなければエラーを出して終了する関数 require_cmd() { local cmd="$1" local hint="${2:-}" # インストール方法のヒント(省略可) if ! command -v "${cmd}" &>/dev/null; then echo "[ERROR] 必要なコマンドが見つかりません: ${cmd}" >&2 if [[ -n "${hint}" ]]; then echo " インストール方法: ${hint}" >&2 fi exit 1 fi }

呼び出し側はシンプルです。

# バックアップスクリプトの先頭で使う例 require_cmd rsync "yum install rsync または apt install rsync" require_cmd tar require_cmd gzip

>&2 でエラーメッセージを標準エラー出力に書くのがポイントです。cronで実行する場合、標準エラー出力だけをメールで受け取る設定にできるため、問題の通知が確実になります。

2. 複数コマンドをまとめて確認する

必要なコマンドが複数ある場合は、配列でまとめて確認すると抜け漏れが防げます。

check_required_cmds() { local cmds=("$@") local missing=0 for cmd in "${cmds[@]}"; do if ! command -v "${cmd}" &>/dev/null; then echo "[ERROR] コマンドが見つかりません: ${cmd}" >&2 missing=1 fi done if [[ "${missing}" -eq 1 ]]; then echo "[ERROR] 必要なコマンドをインストールしてから再実行してください。" >&2 exit 1 fi } # 使い方 check_required_cmds rsync tar gzip openssl

1つでも不足しているコマンドがあれば全件報告してから exit するため、「1個直したらまた別のが足りなかった」を繰り返さずに済みます。

ファイル・ディレクトリ・権限の検証

コマンドが揃っていても、処理対象のファイルがなかったり書き込み権限がなければスクリプトは途中で失敗します。

1. ファイルの存在と読み取り権限

require_file() { local path="$1" if [[ ! -f "${path}" ]]; then echo "[ERROR] ファイルが存在しません: ${path}" >&2 exit 1 fi if [[ ! -r "${path}" ]]; then echo "[ERROR] ファイルを読み取れません(権限不足): ${path}" >&2 exit 1 fi }

-f は「通常ファイルとして存在するか」を確認します。シンボリックリンクが壊れている場合も -f は false を返すため、リンク切れを拾えます。-r は読み取り権限の確認です。root で実行しているか一般ユーザーかによって結果が変わる点に注意してください(root は多くのケースで -r が true になります)。

2. 出力先ディレクトリの存在と書き込み権限

バックアップの出力先ディレクトリは、存在しない場合に作るか、なければエラーにするかを設計で決めます。

# 存在しなければ作成する設計 require_dir() { local path="$1" if [[ ! -d "${path}" ]]; then echo "[INFO] ディレクトリを作成します: ${path}" mkdir -p "${path}" || { echo "[ERROR] ディレクトリの作成に失敗しました: ${path}" >&2 exit 1 } fi if [[ ! -w "${path}" ]]; then echo "[ERROR] ディレクトリに書き込めません(権限不足): ${path}" >&2 exit 1 fi }

mkdir -p 失敗時に || { ... exit 1; } で捕捉するのがポイントです。set -e を使っていれば自動的に落ちますが、エラーメッセージが「mkdir: ... : Permission denied」だけでは文脈がわかりません。自分でメッセージを用意することで、どのスクリプトのどの処理で失敗したかが一目でわかるログになります。

ディスク空き容量のチェック

特に大きなアーカイブを生成するスクリプトでは、容量不足による途中失敗が致命的です。処理開始前に「最低このくらいは空きが必要」という閾値チェックを入れておきます。

# 引数: パス, 最小必要容量(MB) require_disk_space() { local path="$1" local min_mb="$2" # dfの出力から使用可能なブロック数(KB単位)を取得 local avail_kb avail_kb=$(df -k "${path}" | awk 'NR==2 {print $4}') local avail_mb=$(( avail_kb / 1024 )) if [[ "${avail_mb}" -lt "${min_mb}" ]]; then echo "[ERROR] ディスク空き容量が不足しています。" >&2 echo " パス: ${path}" >&2 echo " 必要: ${min_mb} MB / 現在の空き: ${avail_mb} MB" >&2 exit 1 fi echo "[INFO] ディスク空き容量: ${avail_mb} MB (必要: ${min_mb} MB) - OK" }

実行例(/var/backup パスに 500MB 必要な場合):

$ require_disk_space /var/backup 500 [INFO] ディスク空き容量: 12480 MB (必要: 500 MB) - OK

df -k の NR==2 はヘッダー行を除いた1行目(マウントポイントの情報行)を取得します。出力先パスが長い場合は行が折り返されて NR==3 になることがあります。より安全なのは df -k --output=avail "${path}" | tail -1 ですが、--output は一部の古い環境でサポートされていない点に注意してください(Rocky Linux 9.4 / Ubuntu 24.04 では使用可能です)。

環境変数と必須設定値の検証

スクリプトが外部から設定値を受け取る場合(設定ファイルの source・環境変数)、その値が空でないことを確認します。

# 環境変数が空でないことを確認する関数 require_env() { local varname="$1" local value="${!varname}" # 変数名から値を間接参照 if [[ -z "${value}" ]]; then echo "[ERROR] 環境変数 ${varname} が設定されていません。" >&2 exit 1 fi } # 使い方(設定ファイルをsourceした後) source /etc/backup.conf require_env BACKUP_SRC require_env BACKUP_DEST require_env BACKUP_GENERATIONS

${!varname} はBashの間接参照です。require_env "BACKUP_SRC" と呼ぶと、実際には ${BACKUP_SRC} の値を参照します。設定項目が増えてもコードを変えずに対応できます。

完成形:preflight_check 関数を1つにまとめる

ここまで作った4つの検証を1つの preflight_check 関数に集約すると、スクリプトの冒頭に1行書くだけで全項目を確認できます。

#!/bin/bash # backup.sh — 週次フルバックアップスクリプト set -euo pipefail # -------- 設定 -------- BACKUP_SRC="/var/www/html" BACKUP_DEST="/mnt/backup" BACKUP_GENERATIONS=7 MIN_DISK_MB=1024 # 最小空き容量(MB) # -------- preflight チェック -------- preflight_check() { echo "=== preflight チェック開始 ===" # 1. 必要なコマンドの確認 check_required_cmds tar gzip rsync # 2. バックアップ元の確認 require_dir "${BACKUP_SRC}" # 3. バックアップ先の確認(なければ作成) require_dir "${BACKUP_DEST}" # 4. ディスク容量の確認 require_disk_space "${BACKUP_DEST}" "${MIN_DISK_MB}" echo "=== preflight チェック完了 — 処理を開始します ===" } # -------- メイン処理 -------- main() { preflight_check local timestamp timestamp=$(date +%Y%m%d_%H%M%S) local archive="${BACKUP_DEST}/backup_${timestamp}.tar.gz" echo "[INFO] バックアップ開始: ${BACKUP_SRC} -> ${archive}" tar -czf "${archive}" -C "$(dirname "${BACKUP_SRC}")" "$(basename "${BACKUP_SRC}")" echo "[INFO] 完了: ${archive}" } main "$@"

実行時の出力例:

$ bash backup.sh === preflight チェック開始 === [INFO] ディスク空き容量: 38400 MB (必要: 1024 MB) - OK === preflight チェック完了 — 処理を開始します === [INFO] バックアップ開始: /var/www/html -> /mnt/backup/backup_20260910_023001.tar.gz [INFO] 完了: /mnt/backup/backup_20260910_023001.tar.gz

tar コマンドの詳しいオプション(-C でディレクトリを変えてアーカイブする方法など)はtar コマンドの実用例を参照してください。

require_cmd・require_dir・require_disk_space・require_env を共通ライブラリファイル(例: /etc/scripts/lib/preflight.sh)に書き出して source で読み込む設計にすれば、複数のスクリプト間で使い回せます。シェルスクリプトによる自動化の設計パターンをまとめて学ぶなら、シェルスクリプト実践講座 も参考にしてみてください。

トラブルシュート

「df: invalid option -- 'output'」が出る

CentOS 7 や古い RHEL 環境では df --output=avail が使えません。代わりに awk 'NR==2 {print $4}' を使う方式(本記事の例)で対応してください。

「[ERROR] ディレクトリに書き込めません」が出るのに ls では権限がある

実行ユーザーとファイルの所有者グループが一致していない場合や、NFS/SMBマウントのマウントオプションで書き込みが制限されている場合に起こります。ls -la で所有者を確認し、実行ユーザーと一致しているかを確認してください。

require_env で「-bash: !varname: event not found」が出る

対話型シェルでヒストリ展開が有効な場合に起きます。set +H を先に実行するか、スクリプトファイルとして実行(bash script.sh)すれば問題ありません。

本記事のまとめ

確認項目 使う方法 ポイント
コマンドの存在 command -v cmd which より信頼性が高い
ファイルの存在・読み取り [[ -f path ]] / [[ -r path ]] シンボリックリンク切れも検出
ディレクトリの存在・書き込み [[ -d path ]] / [[ -w path ]] なければ mkdir -p で作成も可能
ディスク空き容量 df -k + awk MB単位で閾値と比較する
環境変数・設定値 ${!varname} 間接参照 設定ファイル source 後に確認する
preflight チェックは記述量が増えますが、cron で無人実行するスクリプトほど「なぜ失敗したかがすぐわかる」ことが重要です。本記事の関数群をそのままコピーして使い始め、スクリプトの実績に応じてチェック項目を追加していくのが現実的な進め方です。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
シェルスクリプトによる自動化設計を含む実践的なカリキュラムを提供しています。
>> シェルスクリプト実践講座はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。