「test条件式の書き方がいくつかあって、どれを使えばいいのか分からない」
bashのif文はシェルスクリプトの中で最も使用頻度が高い構文のひとつです。ファイルの存在確認、文字列の比較、数値の大小判定など、スクリプトの自動化ロジックはほぼすべてif文で成り立っています。ところが、testコマンドや[ ]、[[ ]]など複数の書き方があり、初めて学ぶ人が混乱しやすいポイントでもあります。
この記事では、bashのif文とtest条件式の基本から、ファイル操作・文字列・数値・コマンドの終了ステータスを使った実践的な比較パターンまで体系的に解説します。RHEL 9.4 / Ubuntu 24.04 LTSで動作確認済みです。
この記事のポイント
・ bashのif文はtest/[ ]/[[ ]]の3種類があり、用途で使い分ける
・ ファイル確認は-eや-fなど単項演算子、文字列比較は= と!=が基本
・ 数値比較は-eq・-lt・-gtなどtestコマンド専用の演算子を使う
・ 実務では終了ステータス($?)の活用とelifによる多岐分岐が重要
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
bashのif文の基本構文
bashのif文の基本形は以下のとおりです。条件が真(終了ステータスが0)の場合にthenブロックが実行されます。
if 条件; then 処理1 elif 別の条件; then 処理2 else 処理3 fi
bashでは「条件」の部分にtestコマンド、[ ](testの別名)、[[ ]](bash拡張)のいずれかを使います。ifの後の条件は「終了ステータスが0なら真」という仕組みになっているため、コマンドの成否をそのままif文に渡すことも可能です。
1. testコマンドとは
testコマンドはファイルや文字列、数値などの条件を評価し、真なら終了ステータス0、偽なら1を返すコマンドです。[ ]はtestコマンドとまったく同じ動作をします。
# testコマンドと[ ]は同じ意味 test -f /etc/hosts && echo "ファイルが存在する" [ -f /etc/hosts ] && echo "ファイルが存在する"
重要なのは、[ ]を使う場合、スペースが必須であることです。[の後と]の前に必ず半角スペースを入れてください。
# NG: スペースがない(エラーになる) [-f /etc/hosts] # OK: スペースあり [ -f /etc/hosts ]
2. [[ ]](bash拡張)との違い
[[ ]]はbash固有の拡張構文で、[ ]よりも安全で高機能です。主な違いは以下のとおりです。
・変数の引用符:[ ]では変数が空でも問題ないよう "$var" と引用符が必須だが、[[ ]]では $var のままでも安全
・正規表現マッチング:[[ ]]では =~ 演算子で正規表現が使える
・&&・|| の扱い:[[ ]]内では && と || をそのまま使えるが、[ ]内では -a と -o を使う必要がある
# [[ ]]では正規表現マッチングが使える version="9.4.1" if [[ "$version" =~ ^[0-9]+\.[0-9]+ ]]; then echo "バージョン番号の形式が正しい" fi # [[ ]]では変数が空文字でも安全 myvar="" if [[ $myvar == "" ]]; then echo "変数が空です" fi
ポータビリティ(shやdashとの互換性)が必要な場合は[ ]を使い、bashに限定したスクリプトであれば[[ ]]の使用を推奨します。
ファイル・ディレクトリの存在確認
実務で最も頻繁に使うのが、ファイルやディレクトリの存在確認です。
1. 主要なファイル判定演算子
| 演算子 | 意味 | 使用例 |
|---|---|---|
| -e ファイル名 | ファイルまたはディレクトリが存在する | [ -e /etc/hosts ] |
| -f ファイル名 | 通常ファイルが存在する(ディレクトリは除く) | [ -f /etc/passwd ] |
| -d ディレクトリ名 | ディレクトリが存在する | [ -d /var/log ] |
| -r ファイル名 | 読み取り権限がある | [ -r /etc/shadow ] |
| -w ファイル名 | 書き込み権限がある | [ -w /tmp/work.txt ] |
| -x ファイル名 | 実行権限がある | [ -x /usr/bin/python3 ] |
| -s ファイル名 | ファイルが存在し、サイズが0より大きい | [ -s /var/log/messages ] |
| -L ファイル名 | シンボリックリンクが存在する | [ -L /etc/localtime ] |
2. ファイル存在確認の実践例
実際のサーバーでよく使う、設定ファイルのバックアップスクリプトの例です。
#!/bin/bash CONFIG_FILE="/etc/httpd/conf/httpd.conf" BACKUP_DIR="/backup/httpd" # ディレクトリが存在しない場合は作成 if [ ! -d "$BACKUP_DIR" ]; then mkdir -p "$BACKUP_DIR" echo "バックアップディレクトリを作成しました: $BACKUP_DIR" fi # 設定ファイルが存在して読み取り可能か確認 if [ -f "$CONFIG_FILE" ] && [ -r "$CONFIG_FILE" ]; then cp "$CONFIG_FILE" "$BACKUP_DIR/httpd.conf.$(date +%Y%m%d)" echo "バックアップ完了" else echo "エラー: $CONFIG_FILE が存在しないか読み取れません" >&2 exit 1 fi
このスクリプトはRHEL 9.4の実機でテストしたものです。[ ]の中で&&を使う場合は-aを使うのが旧来の書き方ですが、安全のため[ ] と [ ]を&&でつなぐ書き方を推奨します。tarコマンドを使ったアーカイブをこのif文パターンと組み合わせると、バックアップスクリプトがより堅牢になります。
3. 否定条件(!)の使い方
!を使うと条件を反転できます。「ファイルが存在しない場合」の処理でよく使います。
# ロックファイルが存在しない場合のみ処理を実行 LOCK_FILE="/var/run/myapp.lock" if [ ! -f "$LOCK_FILE" ]; then touch "$LOCK_FILE" echo "処理を開始します" # 処理実行... rm -f "$LOCK_FILE" else echo "別のプロセスが実行中です" exit 1 fi
文字列の比較
文字列の比較は、ユーザーへの入力確認や変数の内容チェックでよく使います。
1. 文字列比較演算子一覧
| 演算子 | 意味 | 使用例 |
|---|---|---|
| [ "$a" = "$b" ] | 文字列が等しい | [ "$OS" = "Rocky Linux" ] |
| [ "$a" != "$b" ] | 文字列が等しくない | [ "$USER" != "root" ] |
| [ -z "$a" ] | 文字列が空(ゼロ長) | [ -z "$INPUT" ] |
| [ -n "$a" ] | 文字列が空でない | [ -n "$HOSTNAME" ] |
| [[ "$a" == $b* ]] | グロブパターンマッチ([[ ]]のみ) | [[ "$OSTYPE" == linux* ]] |
| [[ "$a" =~ pattern ]] | 正規表現マッチ([[ ]]のみ) | [[ "$IP" =~ ^[0-9] ]] |
2. 文字列比較の実践例
引数チェックとrootユーザー確認は、実務スクリプトで必ず実装するパターンです。
#!/bin/bash # 実行ユーザーのチェック if [ "$USER" != "root" ] && [ "$(id -u)" -ne 0 ]; then echo "エラー: このスクリプトはrootで実行してください" >&2 exit 1 fi # 引数が空かチェック if [ -z "$1" ]; then echo "使い方: $0 [start|stop|restart]" >&2 exit 1 fi # 引数の内容を判定(caseによる多岐分岐) case "$1" in start) echo "サービスを起動します" ;; stop) echo "サービスを停止します" ;; restart) echo "サービスを再起動します" ;; *) echo "エラー: 不明なオプション '$1'" >&2 exit 1 ;; esac
caseは文字列の多岐分岐に向いており、if/elifが3つ以上続く場合はcaseに書き換えると可読性が上がります。
3. 変数が未定義・空の場合のデフォルト値設定
シェルスクリプトでは変数が未定義の場合のデフォルト値設定パターンも重要です。
# 変数が空または未定義の場合にデフォルト値を設定する LOG_DIR="${LOG_DIR:-/var/log/myapp}" MAX_RETRY="${MAX_RETRY:-3}" echo "ログディレクトリ: $LOG_DIR" echo "最大リトライ回数: $MAX_RETRY" # 空かどうかをif文で判定して設定する別の書き方 if [ -z "$TIMEOUT" ]; then TIMEOUT=30 fi
数値の比較
数値の比較はtestコマンド専用の演算子を使います。文字列比較の=や!=は数値には使わないように注意してください。
1. 数値比較演算子一覧
| 演算子 | 意味 | 使用例 |
|---|---|---|
| [ "$a" -eq "$b" ] | 等しい(equal) | [ "$?" -eq 0 ] |
| [ "$a" -ne "$b" ] | 等しくない(not equal) | [ "$count" -ne 0 ] |
| [ "$a" -lt "$b" ] | 未満(less than) | [ "$disk_usage" -lt 80 ] |
| [ "$a" -le "$b" ] | 以下(less or equal) | [ "$retry" -le "$MAX_RETRY" ] |
| [ "$a" -gt "$b" ] | より大きい(greater than) | [ "$lines" -gt 1000 ] |
| [ "$a" -ge "$b" ] | 以上(greater or equal) | [ "$pid" -ge 1 ] |
2. 数値比較の実践例:ディスク使用率チェック
ディスク使用率が閾値を超えたらアラートを出すスクリプトです。実際のサーバーで使用しているパターンに近い形です。
#!/bin/bash # dfコマンドで/のディスク使用率を取得(RHEL 9.4 / Ubuntu 24.04 確認済み) DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%') echo "現在のディスク使用率: ${DISK_USAGE}%" if [ "$DISK_USAGE" -ge 90 ]; then echo "警告: ディスク使用率が90%を超えています" >&2 exit 2 elif [ "$DISK_USAGE" -ge 80 ]; then echo "注意: ディスク使用率が80%を超えています" exit 1 else echo "ディスク使用率は正常範囲内です" exit 0 fi
このような監視スクリプトをcronに登録することで、自動的にディスク監視を実施できます。マウントポイント別のディスク確認方法と組み合わせると、特定のパーティションを重点監視するスクリプトも作成できます。
コマンドの終了ステータスを使った条件分岐
bashでは、コマンドが正常終了すると終了ステータス0、エラー終了すると1以上の値を返します。if文は終了ステータスが0かどうかを判定するため、コマンドの結果を直接if文に渡せます。
1. 終了ステータスの基本
# pingが通るかチェック if ping -c 1 -W 2 192.168.1.1 >/dev/null 2>&1; then echo "ホストは到達可能です" else echo "ホストに到達できません" fi # grepでパターンがマッチするかチェック if grep -q "ERROR" /var/log/messages; then echo "エラーが検出されました" fi # プロセスが動いているかチェック if pgrep -x "httpd" >/dev/null 2>&1; then echo "httpdは起動中です" else echo "httpdは停止しています" fi
$?は直前のコマンドの終了ステータスを保持する特殊変数です。コマンド実行直後に確認することで、詳細なエラーハンドリングができます。
# システムからの実行例(RHEL 9.4 実機) $ systemctl is-active httpd active $ echo $? 0 $ systemctl is-active nonexistent unknown $ echo $? 3
2. 終了ステータスを使ったサービス起動確認スクリプト
#!/bin/bash SERVICE="httpd" systemctl is-active "$SERVICE" >/dev/null 2>&1 STATUS=$? if [ "$STATUS" -eq 0 ]; then echo "$SERVICE は起動中です" elif [ "$STATUS" -eq 3 ]; then echo "$SERVICE は停止しています" echo "起動を試みます..." if systemctl start "$SERVICE"; then echo "$SERVICE の起動に成功しました" else echo "エラー: $SERVICE の起動に失敗しました" >&2 exit 1 fi else echo "エラー: $SERVICE の状態が不明です(終了ステータス: $STATUS)" >&2 exit 1 fi
ポートの使用状況確認と組み合わせて、サービスのポートが開いているかどうかをif文で分岐させるパターンも実務でよく使います。
複合条件(AND・OR)の書き方
複数の条件を組み合わせる場合、&&(AND)と||(OR)を使います。
1. &&(AND)と||(OR)の使い方
# [ ]の外で&&・||を使う書き方(推奨) if [ -f "$CONFIG" ] && [ -r "$CONFIG" ]; then echo "設定ファイルは読み取り可能です" fi # どちらかの条件が真であれば実行 if [ "$ENV" = "production" ] || [ "$ENV" = "staging" ]; then echo "本番・ステージング環境での実行です" fi # [[ ]]を使う場合は内部に&&・||を書ける if [[ -f "$CONFIG" && -r "$CONFIG" ]]; then echo "設定ファイルは読み取り可能です" fi
2. 一行での簡易if(&&・||ショートサーキット)
スクリプト内で単純な処理であれば、if文を使わず&&・||だけで書く場合もあります。
# ディレクトリが存在しない場合のみ作成 [ -d /var/run/myapp ] || mkdir -p /var/run/myapp # ファイルが存在する場合のみ削除 [ -f /tmp/lockfile ] && rm -f /tmp/lockfile # コマンド成功時にメッセージを表示 cp /etc/hosts /backup/hosts.bak && echo "バックアップ完了"
トラブルシュート・よくあるエラーと対処法
1. [ ]の前後にスペースがない(コマンドが見つからない)
最もよくあるミスです。[ ]はコマンドとして解釈されるため、前後のスペースが必須です。
# エラー例 $ if ["$USER" = "root"]; then echo "root"; fi bash: [root: command not found # 正しい書き方 $ if [ "$USER" = "root" ]; then echo "root"; fi
2. 変数が空の場合に条件評価でエラー(unary operator expected)
変数が空の場合、[ $VAR = "value" ]は[ = "value" ]と解釈されてエラーになります。変数は必ずダブルクォートで囲んでください。
# エラーになるケース(VAR=""の場合) VAR="" if [ $VAR = "hello" ]; then echo "match"; fi # bash: [: =: unary operator expected # 正しい書き方(ダブルクォートで囲む) if [ "$VAR" = "hello" ]; then echo "match"; fi
3. 数値比較で文字列演算子(=)を使ってしまう
数値の比較に=を使うと予期しない動作になることがあります。数値比較には-eq・-lt・-gt等を使ってください。
# 数値を正しく比較する if [ 9 -gt 10 ]; then echo "9が大きい"; else echo "10が大きい"; fi # 正しく "10が大きい" と表示される # 文字列比較で数値を比較すると誤った結果になる場合がある(注意) # "9"と"10"の文字列辞書順では"9"が後になることがある
4. thenの位置(セミコロンの必要性)
# thenを改行後に書く場合はセミコロン不要 if [ -f /etc/hosts ] then echo "exists" fi # セミコロンでifとthenを同じ行にまとめる場合はセミコロンが必要 if [ -f /etc/hosts ]; then echo "exists" fi
本記事のまとめ
| やりたいこと | 構文・演算子 |
|---|---|
| ファイルが存在するか確認 | [ -f ファイル名 ] |
| ディレクトリが存在するか確認 | [ -d ディレクトリ名 ] |
| ファイルが存在して読み取り可能か確認 | [ -f "$FILE" ] && [ -r "$FILE" ] |
| 文字列が空かチェック | [ -z "$VAR" ] |
| 文字列が等しいかチェック | [ "$a" = "$b" ] |
| 数値が一致するか確認 | [ "$a" -eq "$b" ] |
| 数値の大小を比較(未満) | [ "$a" -lt "$b" ] |
| コマンドの成否で分岐 | if command; then ... fi |
| 正規表現マッチング | [[ "$var" =~ pattern ]] |
| グロブパターンマッチング | [[ "$var" == prefix* ]] |
bashのif文とtest条件式は、シェルスクリプト自動化の根幹をなす構文です。ファイル確認・文字列比較・数値比較・終了ステータスの4パターンを押さえておけば、実務で遭遇する条件分岐のほとんどに対応できます。
特に現場でよくあるのが「変数が空のままtestを通してしまう」「数値比較で文字列演算子を使ってしまう」の2パターンです。必ず変数はダブルクォートで囲む習慣をつけ、数値には-eq・-lt・-gtを使うことを覚えておいてください。
bashスクリプトの条件分岐を正確に書けるようになると、バックアップ自動化・デプロイスクリプト・監視ツールなど、現場の定型作業をどんどん自動化できるようになります。ぜひ実際のスクリプトで試してみてください。
Linux無料マニュアルを受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:ncコマンドでLinuxの簡易ファイル転送・チャットを行う方法|listen・connect実例
- この記事の属するカテゴリ:Linuxtips・シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます