シェルスクリプトの基礎 - 条件分岐

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

ここでは、シェルスクリプトにおける条件分岐の記述方法を記載する。

  • if文
    if文を使用することで条件式の結果によって、真偽の分岐を行い、決められた処理を実行することができる。
    条件式には、testコマンド([]でも代用可能)を使用することが多いが、その他のコマンドを使用することも可能である。

    以下は、testコマンドと[]を使用した記述例である。
 # testコマンドを使用
 if test $NUM1 -eq $NUM2 ; then
    echo 'NUM1 equal NUM2'
 fi
 
 # []を使用([の直後と]の直前には半角スペースが必要なので忘れないように注意すること)
 if [ $NUM1 -eq $NUM2 ]; then
    echo 'NUM1 equal NUM2'
 fi


  • case文
    case文は判定対象となる値と事前に作成した複数の条件を上から順に比較して、マッチした条件の処理を実行させることができる。
    どの条件にもマッチしない場合は何も処理を行わない。
 casein
    条件1)
       処理1
       ;;
    条件2)
       処理2
       ;;
    *)         # <---条件1と条件2に当てはまらない場合に選択される
       処理3
       ;;
 esac



if文

条件分岐 if then fi

この条件分岐は、条件式が真の場合のみ指定された処理を行い、それ以外の場合は何も行わない。
ここでは、NUM1とNUM2の値を比較して、等しい場合にメッセージを表示するというスクリプトを記述する。

 #!/bin/bash
 NUM1=10
 NUM2=10
 
 if [ $NUM1 -eq $NUM2 ]; then
    echo 'NUM1 equal NUM2'
 fi


条件分岐 if then else fi

この条件分岐は、条件式が真の場合に処理1を行い、それ以外の場合は処理2を行う。
ここでは、NUM1とNUM2の内容の真偽を判別し、同じ場合と異なる場合によって表示させるメッセージを変更するというスクリプトを記述する。

 #!/bin/bash
 NUM1=10
 NUM2=10
 
 if [ $NUM1 -eq $NUM2 ]; then
    echo 'NUM1 equal  NUM2'
 else
    echo 'NUM1 not equal NUM2'
 fi


条件分岐 if then elif then else fi

この条件分岐は、条件式1が真の場合は処理1を行い、条件式1が偽で条件式2が真の場合は処理2を行い、それ以外の場合は処理3を行う。
ここでは、NUM1とNUM2の値を比較して、内容が等しい、NUM1の方が大きいか小さいかによって表示するメッセージを変えるというスクリプトを記述する。

 #!/bin/bash
 NUM1=20
 NUM2=10
 
 if [ $NUM1 -eq $NUM2 ]; then
    echo 'NUM1 equal  NUM2'
 elif [ $NUM1 -gt $NUM2 ]; then
    echo 'NUM1 greater than  NUM2'
 else
    echo 'NUM1 smaller than NUM2'
 fi


短絡演算子

&&を短絡演算子として使用する。
if文の条件式が真(true)になる場合のみ簡単な処理を行うには、&&を使用してif文の代わりにすることができる。

 read -p "ごみ箱を空にしますか? [y/n]" input
 [ "$input" = 'Y' -o "$input" = 'y' ] && rm ~/trash/*


上記のシェルスクリプトは、以下のシェルスクリプトと同様に振るまう。

 read -p "ごみ箱を空にしますか? [y/n]" input
 if [ "$input" = "Y" -o "$input" = "y" ]; then
    rm ~/trash/*
 fi


testコマンドの比較条件

testコマンドは、条件式の真偽を判別して、その結果を返すコマンドである。
使用できる比較条件は数多くあるが、使用頻度の高いものを抜粋して記載する。

数値の比較条件
条件 比較内容
数値1 -eq 数値2 数値1と2が等しい場合に真
数値1 -ne 数値2 数値1と2が等しくない場合に真
数値1 -gt 数値2 数値1が数値2より大きい場合に真
数値1 -ge 数値2 数値1が数値2以上ならば真
数値1 -lt 数値2 数値1が数値2より小さい場合に真
数値1 -le 数値2 数値1が数値2以下の場合に真


文字の比較条件
条件 比較内容
-n 文字列 文字列の長さが0より大きい場合は真
-z 文字列 文字列の長さが0ならば真
文字列1 = 文字列2 文字列1と2が等しい場合は真
文字列1 != 文字列2 文字列1と2が異なる場合は真


ファイルの比較条件
条件 比較内容
ファイル1 -nt ファイル2 ファイル1がファイル2より新しく作成・更新されていた場合は真
ファイル1 -ot ファイル2 ファイル1がファイル2より古く作成・更新されていた場合は真
-a <ファイル> <ファイル>が存在していれば真
-d <ファイル> <ファイル>が存在してディレクトリであれば真
-e <ファイル> <ファイル>が存在していれば真
-f <ファイル> <ファイル>が存在してファイルならば真
-r <ファイル> <ファイル>が存在して読み込み許可されていれば真
-w <ファイル> <ファイル>が存在して書き込み許可されていれば真
-x <ファイル> <ファイル>が存在して実行可能であれば真
-L <ファイル> <ファイル>が存在してシンボリックリンクであれば真
-s <ファイル> ファイルサイズが1以上であれば真


AND / OR / NOT
条件 比較内容
! 条件式 条件式が偽なら真(NOT)
条件式1 -a 条件式2 条件式1と2のどちらも真なら真(AND)
条件式1 -o 条件式2 条件式1か2のどちらかが真なら真(OR)


if 文の応用

条件式に任意のコマンドを使用する。

if文は、条件式に指定したコマンドの終了ステータスを判定して、条件分岐を行う制御文である。
したがって、条件式にはtestコマンド以外にも、lsコマンドやgrepコマンド等の一般的なコマンドを使用することもできる。

 if echo "$var" | grep -sq "hoge"; then
    echo "hogeが見つかりました。"
 fi
 # または
 if echo "$var" | grep "hoge" 1>/dev/null 2>/dev/null; then
    echo "hogeが見つかりました。"
 fi


多くの場合、条件式に指定するコマンドで実行結果の出力を行う必要が無いため、
出力を抑制するオプションを指定するか、または、1>/dev/null 2>/dev/nullを指定して全ての出力を非表示にするとよい。
例えば、grepコマンドを条件式に指定する場合、-sオプションと-qオプションを同時に指定することで、エラー出力と標準出力を抑制することができる。

条件式にコマンドを指定しない場合、if文により、直前のコマンドの終了ステータスを表す特殊変数$?を判定する。

 # コマンドの実行結果をif文で判定する
 echo "$var" | grep -sq "hoge"
 
 if [ $? -eq 0 ]; then
    echo "hogeが見つかりました。"
 fi


終了ステータスを使い回す場合は、任意の変数に格納して終了ステータスを退避することで、特殊変数$?が他のコマンドによって上書きされても影響を受けない。

 echo "$var" | grep -sq "hoge";
 result=$?
 
 # ...他の処理
 
 if [ $result -eq 0 ]; then
    echo "hogeが見つかりました。"
 fi


以下の例では、スーパーユーザかどうかを確認している。
スーパーユーザのIDは常に0であることを利用して、それを確認する。

 # スーパーユーザのみシェルスクリプトの実行を許可する場合
 if [ "$(id -u)" -ne 0 ]; then
    echo -e "スーパーユーザではありません"
    exit 1
 fi
 
 # 一般ユーザのみシェルスクリプトの実行を許可する場合
 if [ "$(id -u)" -eq 0 ]; then
    echo "一般ユーザではありません"
    exit 1
 fi




case文

条件の指定について

条件の指定にはワイルドカードを使用することができる。

*	すべての文字列にマッチ
?	何か1文字にマッチ
???  : 何か3文字の文字列にマッチ
???* : 3文字以上の文字列にマッチ
[ ]	[]に囲まれた文字や数字等のどれかにマッチ
[! ]	[]囲まれていない文字や数字等のどれかにマッチするのにマッチ
[ - ]	「-」で設定された範囲の文字や数字にマッチ


注意
OR条件を使用する場合は、条件1 | 条件2と指定することで、複数の条件をまとめて指定することができる。
*自体をマッチさせる場合は、\*、"*"、'*'とエスケープする。
?自体をマッチさせる場合は、\?、"?"、'?'とエスケープする。


使用例
abc*     : abcで始まる文字列にマッチ
a*bc     : aで始まり、bcで終わる文字列すべてにマッチ
a?c      : 最初が「a」で始まり最後が「c」で終わる3文字の文字列にマッチ
[ ]      : []に囲まれた文字や数字等のどれかにマッチ
[Aa]     : Aまたはaにマッチ
[Aa][Bb] : AB、Ab、aB、abにマッチ
[! ]     : []に囲まれていない文字や数字等のどれかにマッチ
[!Aa]    : 「A」と「a」以外にマッチ
[a-z]    : アルファベットの小文字にマッチ
[A-Z]    : アルファベット大文字にマッチ
[a-zA-Z] : アルファベットの小文字と大文字にマッチ
[0-9]    : 数字の0から9にマッチ
ABC | abc : 「ABC」か「abc」のどちらかにマッチ


サンプルコード

入力したキーによって、アルファベット、数字、その他の判別を行いメッセージを表示するシェルスクリプトを記述する。
Tを入力すると、[a-zA-Z]の条件にマッチするので、Alphabet enteredと表示される。
0を入力すると、[0-9]の条件にマッチするので、Number enteredと表示される。
アルファベットや数字以外の文字を入力すると、*の条件にマッチするので、No alphabet or number enterdと表示される。

 #!/bin/bash
 
 echo 'Please input alphabet or number'
 read key
 
 case "$key" in
    [a-zA-Z])  echo 'Alphabet entered' ;;
    [0-9])     echo 'Number entered' ;;
    *)         echo 'No alphabet or number enterd' ;;
 esac