シェルとシェルスクリプト 4  条件分岐、繰り返し、サブルーチン

条件分岐

 プログラミングでは、条件に剃って挙動を切り替える 「 条件分岐 」 を多用する。シェルスクリプトでも利用することができる。

if 文

比較などによる条件分岐を行う場合はif 文を利用する。

$ if 条件式1 then ... elif 条件式2 ... else ...fi

 elif と else は省略可能である。 elif は別の条件で判断したい場合に利用する。 else は条件に当てはまたなかった場合に実行される。if 文は fi で終了する。

条件式 if 文で利用される条件式
演算子 比較内容
a == b a と b が等しければ真
a != b a と b が等しくなければ真
数値比較を行う演算子
演算子 比較内容
a -eq b a と b が等しければ真 ( equal to )
a -ne b a と b が等しくなければ真 ( not equal to )
a -ge b a が b 以上であれば真 ( greater than or equal to )
a -le b a が b 以下であれば真 ( less than or equal to )
a -gt b a が b より大きい値であれば真 ( greater then )
a -lt b a が b 未満であれば真 ( less than )

ファイル属性の確認

 ファイル属性の確認は次のように行う。

$ if test -d パス ; then ...

 -d の部分がファイル属性確認の演算子にあたる。 -d はディレクトリであるかの判定を行うので、この if 文全体で、 「 パスがディレクトリであれば真の値を返す 」 という条件式になる。

 ファイルの属性確認演算子は以下のようなものが利用できる。

演算子 内容
-f ファイル名 通常ファイルなら真
-d ファイル名 ディレクトリなら真
-e ファイル名 ファイルが存在するなら真
-L ファイル名 シンボリックなら真
-r ファイル名 読み取り可能ファイルなら真
-w ファイル名 書き込み可能ファイルなら真
-x ファイル名 ファイルが存在して、実行権限があれば真
-s ファイル名 サイズが0より大ければ真

 なお、test コマンドは [] を使って記述することもできる。

$ if [ 条件節 ]; then ...
$ if test [ 条件節 ] ; then ...

複数の条件式を重ねる

 条件分岐指定いる場合、複数の条件を重ねることができる。条件Aと条件Bが同時に成立してい必要がある時は 「 条件Aかつ条件Bが成立 」 ということで、論理積 ( =AND ) が用いられる。

 同じく、 「 条件Aもしくは条件Bが成立 」 の場合は論理和 ( =OR ) が用いられる。シェルスクリプトにおいて、論理積論理和の書き方は2通り存在する。

論理積

 論理積は -a を用いる場合と、 && を用いる場合がある。

$ [ 条件A -a 条件B -a 条件C ] ...
$ [ 条件A ] && [ 条件B ] && [ 条件C ] ] ...

-a と && は、それぞれ [ ] の内側か外側かで、使われ方が変わることに注意する。

論理和

論理和を表す記号は -o と || である。

$ [ 条件式A -o 条件式B -o 条件式C ]...
$ [ 条件式A ] || [ 条件式B ] || [ 条件式C ]...

 論理積の時と同様に -o と || はそれぞれ [ ] の内側か外側かで使われ方が変わる。

一体多の条件式

 一体多の分岐を行うことを考えてみる。 if 文を用いた場合、一体多の分岐は以下のようになる。

if 条件式 then

elif 条件式 then

elif 条件式 then

fi

シェルスクリプトでは、case 文が用意されており、一体多の分岐が記述できるようになっている。

case 変数 in
         値A)
                                処理1;;
         値B)
                                処理2;;
esac

 変数の値が値Aである時、処理1が実行される。最後は case 文の逆からの記述である esac で終わることが重要である。値はパイプ ( | ) で区切って複数指定することもできる。

実行例

$ vi case.sh
( インサートモードで以下を入力 )
#!/bin/bash
  
case $1 in
        a|A)
                echo "引数にaまたはAが入力されました";;
        b|B)
                echo "引数にbまたはBが入力されました";;
esac

シェルスクリプトを実行する。

$ ./case.sh a
引数にaまたはAが入力されました

$ ./case.sh b
引数にbまたはBが入力されました

 また、どの値にもマッチしなかった場合の処理を記述するには、値にアスタリスク ( * ) を用いる。

実行例

$ vi defaultcase.sh
( インサートモードで以下を入力 )

#!/bin/bash

case $1 in
        1)
            echo "引数に1が入力されました";;
        2)
            echo "引数に2が入力されました";;
        *)
            echo "1,2以外が入力されました";;
esac

シェルスクリプトを実行する。

$  ./defaultcase.sh 1
引数に1が入力されました

$ ./defaultcase.sh 2
引数に2が入力されました

$ ./defaultcase.sh 0
1,2以外が入力されました
( どの条件にもマッチしない場合、値 * の処理が実行される )

繰り返し

 プログラミングにおいて、条件分岐と同じくらい重要な機構が繰り返しである。同じ処理を繰り返し行い、ある条件が成立した時に終了する、という形式が用いられる。シェルスクリプトで用いられる繰り返しは以下の3通りである。

for 文

  for 文は値を列挙し、それを対象に処理を繰り返す。

$ for 変数 in 値のリスト
do
  処理
done

 値のリストとは、文字を羅列したものもあれば、実行結果を使うこともできる。

実行例

$ for i in a b c d 
for> do
for> echo $i
for> done
a
b
c
d

 これは、値のリストとして、a b c d が渡され、i = a を行い echo $1 、次に $1 、次に...を繰り返した結果である。値のリストとしてコマンドの実行結果を使うことができ、以下のように、i に ls の実行結果を代入してループが実行される。

$ for i in `ls`
for> do
for> echo $i
for> done
Applications
Desktop
Documents
Downloads
HTML
CSS
JavaScript
...
while/until 文

 while 文は条件が成立している間ループを繰り返す ( 条件が成立しなくなったら終了 ) という処理で利用される。

 until 文はそれの反対で条件が成立していない間ループを繰り返す ( 条件が成立したら処理を終了 ) という用途で使われる。

$ while 条件式
do
  処理
done

$ until 条件式
do
  処理
done

 C言語の for 文のようなループ分をシェルスクリプトで実現するには、expr コマンドを用いてループカウンタ用の変数をインクリメント ( またはデクリメント ) しながら、while/until 文で処理を行う。

実行例

$ vi loop.sh

#!/bin/bash
  
count=1
while [ $count -le 10 ]
do
     echo この処理は $count 回実行されました
     count=`expr $count + 1`
done

 count=1 で、カウンタ用の変数 count に初期値1を設定する。while [ $count -le 10 ] で、シェル変数 count が10以下の間、処理を繰り返す。

シェルスクリプトを実行

$ ./loop.sh
この処理は 1 回実行されました
この処理は 2 回実行されました
この処理は 3 回実行されました
この処理は 4 回実行されました
この処理は 5 回実行されました
この処理は 6 回実行されました
この処理は 7 回実行されました
この処理は 8 回実行されました
この処理は 9 回実行されました
この処理は 10 回実行されました

select 文

   select 文はユーザに対して数値による入力を促す。

$ select 変数 in リスト
do
   処理
done

実行例

$ select name in "apple" "banana" "orange"
select> do
select> echo "You selected $name";
select> done
1) apple   2) banana  3) orange  
?# 1
You selected apple
?# 2
You selected banana
?# 3
You selected orange
( control + c で終了する )

繰り返しの制御

 break や continue を用いることで、繰り返しを制御することができる。break は繰り返しを終了して、continue は繰り返しの先頭に戻る役割がある。

実行例

$ vi sample.sh
( インサートモードで以下を入力 )

while true
do
 echo "Continue? (y/n)"
 read input
 case $input in
 n) break
    ;;
 y) continue
    ;;
 *) echo "Please input y or n."
    ;;
 esac
done

シェルスクリプトを実行する

$ ./sample.sh
Continue? (y/n)
y ( y を入力する )

Continue? (y/n) ( 繰り返しの先頭に戻る )
a ( a を入力する )

Please input y or n. ( どの値にもマッチしなかった場合の処理が実行される )
n ( n を入力すると終了する )

$

サブルーチン

 プログラミングをする上で、一連の処理をまとめて、再利用できるようにしたものを、サブルーチンと言う。サブルーチンは言語により様々な呼ばれ方をされていて、シェルスクリプトでは関数と呼ばれている。

関数

 関数は、引数と呼ばれるデータを与え、処理をして結果を返すという機能の集まりである。

$ function 関数名
{
  処理
}

$ 関数名()
{
  処理
}

 両者ともに働きは同じである。引数は、実行時に関数名に続けて記述する。引数は関数の内部で、$1 、 $2 で参照することができる。

return 文

 シェルスクリプトの関数で、結果を返すときはreturn 文を実行する。

$ return 変数名

 return 文を実行すると、関数内での処理はそこで終了し、変数が関数に呼び出され元に戻される。