Bashシェルスクリプト/制御文 の変更点


*''制御文'' [#k6f959af]

[[dokuwiki.fl8.jp転載済み>http://dokuwiki.fl8.jp/doku.php/bash/%E5%88%B6%E5%BE%A1%E6%96%87]]

**''if文'' [#a310f3fa]
if文は、ある条件を指定して、それが真(0)が偽(1)かで処理を分岐する制御文です。~
&color(red){※else、elifは省略可能です。thenは必須となります。};
***構文 [#u8e00d3e]
 if [ 条件1 ]; または if test 条件
 then
         条件1が成立した時に実行するコマンド
 elif [ 条件2 ];
 then
         条件1が不成立で条件2が成立した時に実行するコマンド
 else
         条件1と条件2が不成立の時に実行するコマンド
 fi

***条件 [#ta6fdfe4]
■ファイル形式のチェック
 -b  File            指定したFileがブロックデバイスファイルなら真である。 
 -c  File            指定したFileがキャラクタデバイスファイルなら真である。 
 -d  File            指定したFileがディレクトリなら真である。 
 -f  File            指定したFileが通常ファイルなら真である。 
 -L  File            指定したFileがシンボリックリンクなら真である。 
 -p  File            指定したFileが名前付きパイプなら真である。 
 -S  File            指定したFileがソケットなら真である。 

■ファイルパーミッションのチェック
 -g  File            指定したFileにSGIDがセットされていれば真である。 
 -k  File            指定したFileにスティッキービットがセットされていれば真である。 
 -r  File            指定したFileが読み取り可能なら真である。 
 -u  File            指定したFileにSUIDがセットされていれば真である。 
 -w  File            指定したFileが書き込み可能なら真である。 
 -x  File            指定したFileが実行可能なら真である。 

■その他のファイルのチェック
 -e  File            指定したFileが存在すれば真である。 
 -s  File            指定したFileのファイルサイズが0より大きければ真である。 

■文字列のチェック
 -n  文字列          文字列の長さが0より大きければ真である。 
 -z  文字列          文字列の長さが0であれば真である。 
 文字列1 = 文字列2   2つの文字列が等しければ真である。 
 文字列1 != 文字列2  2つの文字列が等しくなければ真である。 


■数値のチェック
 数値1  -eq  数値2   2つの数値が等しければ真である。 
 数値1  -ge  数値2   数値1が数値2以上であれば真である。 
 数値1  -gt  数値2   数値1が数値2より大きいのであれば真である。 
 数値1  -le  数値2   数値1が数値2以下であれば真である。 
 数値1  -lt  数値2   数値1が数値2未満であれば真である。 
 数値1  -ne  数値2   2つの数値が等しくなければ真である。 

■論理結合
 !条件               条件が偽であれば真である。 
 条件1 -a 条件2    条件1と条件2の両方が真であれば真である。 
 条件1 -o 条件2    条件1と条件2のどちらかが真であれば真である。 

***if文 使用例 [#df4c7751]
■[[testコマンド>Unixコマンド/test]]による、if分岐
 test01.sh
  
 #!/bin/sh
 
 if test $1 -le 0
 then
   echo "Number is Less than or equal 0."
 else
   echo "Number is grater than 0."
 fi
実行例
 $ sh test01.sh 6
 Number is Less than or equal 0.
 $ sh test01.sh 8
 Number is grater than 0.
**''while文'' [#ae6d7922]
while文は、ある条件を提示してその条件を満たしている間、同一の処理を何度も繰り返すループ文です。~
while文は条件の終了状態が真である場合は doとdoneの間に記述されたコマンドを実行します。~
そして条件の終了状態が偽になり次第ループから抜けます。~
***''構文'' [#n8dc8997]
 while 条件 
 do 
 	繰り返し実行されるコマンド	
 done 

***''無限ループを使う'' [#yadc139e]
while文を使うと無限ループを簡単に作れます。~
「いつも真」になるようにしてやれば、いいだけです。~
|無限ループ記述例|~|h
|記述例|説明|h
|while true; do . . . .|trueコマンドはいつも真(0)を返す|
|while [1]; do . . . .|「test 1」はいつも真(0)を返す|
|while :; do . . . .|:コマンドは「何もしない」コマンド。終了コードは真(0)を返す。|

***''while文 使用例'' [#qafd8a32]
■変数Aに1を入れておいて、while文の条件を10以下なら真にしておく~
 変数Aが10以下であれば、「まだ10より小さい」と表示させる。~
 exprで変数Aに1づつ足しているので、変数Aが10になればwhile文を抜ける。
 while_test01.sh
 
 #!/bin/sh
 A=1
 while [ $A -lt 10 ]
 do
   echo "まだ10より小さい"
   A=`expr $A + 1`
 done
 echo "10を超えました。"
実行例
 $ ./while_test01.sh 
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 まだ10より小さい
 10を超えました。
■リモートホストにpingを送り続ける
 while_test02.sh
 
 #!/bin/sh
 HOST="example.jp"
 INTERVAL=600
 
 while true
 do
   echo %%%%%
   date
   ping -c1 $HOST
   echo %%%%%
   sleep $INTERVAL
 done
実行例 10分おきに実行し続ける。
 $ ./while_test02.sh
 %%%%%
 2006年 6月21日 水曜日 23時28分03秒 JST
 PING dynabook.mydomain.co.jp (192.168.1.11): 56 data bytes
 64 bytes from 192.168.1.11: icmp_seq=0 ttl=64 time=0.751 ms
 
 --- dynabook.mydomain.co.jp ping statistics ---
 1 packets transmitted, 1 packets received, 0% packet loss
 round-trip min/avg/max/stddev = 0.751/0.751/0.751/0.000 ms
 %%%%%
 %%%%%
 2006年 6月21日 水曜日 23時38分03秒 JST
 PING dynabook.mydomain.co.jp (192.168.1.11): 56 data bytes
 64 bytes from 192.168.1.11: icmp_seq=0 ttl=64 time=0.751 ms
 
 --- dynabook.mydomain.co.jp ping statistics ---
 1 packets transmitted, 1 packets received, 0% packet loss
 round-trip min/avg/max/stddev = 0.751/0.751/0.751/0.000 ms
 %%%%%
 %%%%%
 2006年 6月21日 水曜日 23時48分03秒 JST
 PING dynabook.mydomain.co.jp (192.168.1.11): 56 data bytes
 64 bytes from 192.168.1.11: icmp_seq=0 ttl=64 time=0.751 ms
 
 --- dynabook.mydomain.co.jp ping statistics ---
 1 packets transmitted, 1 packets received, 0% packet loss
 round-trip min/avg/max/stddev = 0.751/0.751/0.751/0.000 ms
 %%%%%
***''while文 ファイルの内容を行単位で読み込む'' [#c7841ab6]
while文を使うと、ファイルからデータを順番に読み込みながら、そのファイルが終了するまでループするという処理ができます。~
この機能は非常に便利なので覚えておくといいでしょう。~
■構文(fileから読み込みfileの行が終わるまでループします。)
 while read LINE
 do
   ・(ループ処理)
   ・(ループ処理)
   ・(ループ処理)
 done < file
■例~
test.txtを一行づつ読み込みechoコマンドで標準出力に出力します。
 while_test03.sh

 #!/bin/sh
 FILE=test.txt
 while read LINE
 do
  echo $LINE
 done < $FILE
test.txtの内容は下記のようになっています。
 $ cat test.txt 
 月
 火
 水
 木
 金
 土
 日
実行するとこのように一行ずつ表示されます。
 $ ./while_test03.sh
 月
 火
 水
 木
 金
 土
 日
**''case文'' [#y4c25b2a]
case文は、文字列がパターンと合致するかによって分岐する制御文です。~
if文を駆使すれば同様の処理も可能ですが、文字列に対する複数の分岐を考える場合はcase文の方がわかりやすく融通もききます。~
合致するパターンがあれば、)から;;までに指定されているコマンド行を実行します。~
通常は、パターンの最後には*(ワイルドカード)を指定し、どのパターンにも合致しなかった場合の処理を書いておきます。~
case文の終了は綴りを逆さまにしたesacです。~
***構文 [#ac04c384]
 case string in
   pattern_1)
     commands1
   ;;
   pattern_2)
     commands2
   ;;
 esac
***case文で使用するパターン例 [#u0a4133c]
 表現の形式         意味
 string)            stringという文字列そのもの
 string1|string2)   string1あるいはstring2という文字列
 str*)              先頭がstrの文字列
 *str)              末尾がstrの文字列
 [a-z]*)            先頭がアルファベット小文字
 [!0-9]*)           先頭が数字以外の文字列
 [yY]               yかY
 ???)               3文字の文字列
 *)                 すべて

***例 [#t80d3c41]
 case_test01.sh
 
 #!/bin/sh
 
 case $1 in
     [a-z]*)
        echo "アルファベット小文字で始まってます。"
     ;;
     [A-Z]*)
        echo "アルファベット大文字で始まってます。"
     ;;
     [0-9]*)
        echo "数字で始まってます。"
     ;;
 esac
実行例
 $ ./case_test01.sh snoopy
 アルファベット小文字で始まってます。
 
 $ ./case_test01.sh Apple
 アルファベット大文字で始まってます。
 
 $ ./case_test01.sh 1999
 数字で始まってます。
***case文 キーボードからの入力で処理を分ける [#o1768272]
 case_test02.sh
 
 #!/bin/sh
 
 echo -n "Please enter Yes or No _"
 read RESPONSE
 
 case $RESPONSE in
          [Yy][Ee][Ss])  echo "You answered Yes." ;;
          [Nn][Oo])      echo "You ansered No." ;;
           *)            echo "Please enter Yes or No." ;;
 esac
実行例
 $ ./case_test02.sh
 Please enter Yes or No _Yes
 You ansered Yes.
 
 $ ./case_test02.sh
 Please enter Yes or No _No
 You ansered No.
 
 AAAと入力した場合、どれにも合致しないので、*の行に当てはまる。
 $ ./case_test02.sh
 Please enter Yes or No _AAA
 Please enter Yes or No.

**''select文'' [#cf928395]
select文はbashで追加となった制御文です。~
項目をリストし、番号を選んで処理させるというメニュー形式の対話的な画面が簡単に作れます。~
[[case文>#y4c25b2a]]でも同じようなメニュー画面を作成することもできますが、大掛かりなスクリプトになってしまいます。~
select文を使うとメニュー画面を簡単に作成できるメリットがあります。~
***''構文'' [#g5cab582]
 select variable in menulists
 do
   commands
 done
***例 [#x3f68dd8]
&color(red){※select文の場合は必ずbashを指定しなければなりません。};~
&color(red){ ×#!/bin/sh}; &color(blue){○#!/bin/bash};
 select_test01.sh
 
 #!/bin/bash
 
 select i in Item1 Item2 Item3
 do
   echo "You entered $i."
 done
実行例
 $ ./select_test01.sh
 1)Item1            ←メニューが現れる
 2)Item2
 3)Item3
 #? 1               ←#?で入力待ちになる。
 You entered Item1.
**''for文'' [#tf5426e7]
for文は、同一の処理を何度も繰り返すループ文です。~
引数の要素を順番に変数に渡していく事で、繰り返し処理に変化を付けます。~
引数の要素がひととおり巡ったらforループを抜けます。~
ループの回数は引数の要素数で決まります。~

***''構文'' [#q0bfdb99]
 for 変数 in 引数・・・
 do
 	繰り返し実行されるコマンド
 done
***例 [#a36fd654]
 for_test01.sh
 
 #!/bin/sh
 
 for i in 0 1 2 3 4 5
 do
   echo $i
 done
実行例
 $ ./for_test01.sh
 0
 1
 2
 3
 4
 5 
***''構文(C言語風)'' [#q22da38a]
bashではC言語で同じみの形式でfor文が使えます。~
expr1を前提とし、条件expr2が成立するまで処理を繰り返し、その間expr3を実行するという形式です。
 for (( expr1 ; expr2 ;expr3 ))
 do
 	繰り返し実行されるコマンド
 done
***例 [#ibb7c56a]
変数iを0として変数iが10より小さい間変数iに1づつ足していく。
 for _test02.sh
 
 #!/bin/sh
 
 for (( i=0 ; i<10 ; i++ ))
 do
   echo $i
 done
実行例
 $ ./for_test02.sh
 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
**''continueコマンド'' [#q6e0ba8b]
[[for文>#tf5426e7]]や[[while文>#ae6d7922]]などの処理を途中で中断し、処理をループの先頭に戻すコマンドがcontinueです。~
書式も[[breakコマンド>#j6063ac1]]と同じで、いくつ前のループ文の先頭へ戻るかを引数で渡せます。~

***''構文'' [#r8f7bd6e]
 continue 実行を継続したいループまでの深さ

***''例'' [#f88ec009]
以下のようにfor文が3つの[[ネスト>用語/nest]]になっている場合2を指定すると"for a"のループから実行を継続します。
 #!/bin/sh

 for a
 do
	for b
	do
		for c
		do
			if [ $c = redhat ];
			then
				continue 2
			fi
		done
	done
 done

**''breakコマンド'' [#j6063ac1]
[[for文>#tf5426e7]]や[[while文>#ae6d7922]]から強制的に抜けるコマンドがbreakコマンドです。~
もちろん[[select文>#cf928395]]やuntil文からも抜け出せます。~
continueコマンドがループの先頭に戻るのに対し、breakコマンドはループを抜けます。~
breakコマンドは、引数がないとループ文を1つだけ抜けます。~
[[ネスト>用語/nest]]した複数のループを一挙に抜けたいときは、いくつのループを抜けるかという数を引数として指します。~
※引数に指定した数値の方がループの[[ネスト>用語/nest]]より多かったときは一番上位のループを抜けますが、エラーにはなりません。

***''構文'' [#w4a133d8]
 break 抜けたいループの深さ

***''例'' [#a213ab9a]
以下のようにfor文が3つの[[ネスト>用語/nest]]になっている場合3を指定すると全てのループから抜けます。
 #!/bin/sh
 
 for a
 do
	for b
	do
		for c
		do
			break 3			
		done
	done
 done