====== 01 Bash - 制御文 ====== ===== if文 ===== if文は、ある条件を指定して、それが真(0)が偽(1)かで処理を分岐する制御文です。\\ ※else、elifは省略可能です。thenは必須となります。 ==== 構文 ==== if [ 条件1 ]; または if test 条件 then 条件1が成立した時に実行するコマンド elif [ 条件2 ]; then 条件1が不成立で条件2が成立した時に実行するコマンド else 条件1と条件2が不成立の時に実行するコマンド fi ==== if文 使用例 ==== 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. ===== 条件 ===== ^ ファイル形式のチェック ^^ |-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つの数値が等しければ真である。|equal to| |数値1 -ne 数値2|2つの数値が等しくなければ真である。|not equal to| |数値1 -ge 数値2|数値1が数値2以上であれば真である。|greater than or equal to| |数値1 -gt 数値2|数値1が数値2より大きいのであれば真である。|greater than| |数値1 -le 数値2|数値1が数値2以下であれば真である。|less than or equal to| |数値1 -lt 数値2|数値1が数値2未満であれば真である。|less than| ^ 論理結合 ^^ |!条件|条件が偽であれば真である。| |条件1 -a 条件2|条件1と条件2の両方が真であれば真である。(AND)| |条件1 -o 条件2|条件1と条件2のどちらかが真であれば真である。(OR)| ===== for文 ===== for文は、同一の処理を何度も繰り返すループ文です。\\ 引数の要素を順番に変数に渡していく事で、繰り返し処理に変化を付けます。\\ 引数の要素がひととおり巡ったらforループを抜けます。\\ ループの回数は引数の要素数で決まります。 ==== 構文 ==== for 変数 in 引数・・・ do 繰り返し実行されるコマンド done ==== for文 例1 ==== 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 ===== for文(C言語風) ===== bashではC言語で同じみの形式でfor文が使えます。\\ expr1を前提とし、条件expr2が成立するまで処理を繰り返し、その間expr3を実行するという形式です。 ==== 構文 ==== for (( expr1 ; expr2 ;expr3 )) do 繰り返し実行されるコマンド done ==== for文(C言語風) 例1 ==== 変数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 ===== while文 ===== while文は、ある条件を提示してその条件を満たしている間、同一の処理を何度も繰り返すループ文です。\\ while文は条件の終了状態が真である場合は doとdoneの間に記述されたコマンドを実行します。\\ そして条件の終了状態が偽になり次第ループから抜けます。 ==== 構文 ==== while 条件 do 繰り返し実行されるコマンド done ==== 無限ループを使う ==== while文を使うと無限ループを簡単に作れます。\\ 「いつも真」になるようにしてやれば、いいだけです。 無限ループ記述例 ^ 記述例 ^ 説明 ^ |while true; do . . . .|trueコマンドはいつも真(0)を返す| |while [1]; do . . . .|「test 1」はいつも真(0)を返す| |while :; do . . . .|コマンドは「何もしない」コマンド。終了コードは真(0)を返す。| ==== while文 使用例 ==== 変数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文 ファイルの内容を行単位で読み込む == 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文 ===== case文は、文字列がパターンと合致するかによって分岐する制御文です。\\ if文を駆使すれば同様の処理も可能ですが、文字列に対する複数の分岐を考える場合はcase文の方がわかりやすく融通もききます。\\ 合致するパターンがあれば、)から;;までに指定されているコマンド行を実行します。\\ 通常は、パターンの最後には*(ワイルドカード)を指定し、どのパターンにも合致しなかった場合の処理を書いておきます。\\ case文の終了は綴りを逆さまにしたesacです。 ==== 構文 ==== case string in pattern_1) commands1 ;; pattern_2) commands2 ;; esac ==== case文で使用するパターン例 ==== ^ 表現の形式 ^ 意味 ^ |string)|stringという文字列そのもの| |string1|string2)|string1あるいはstring2という文字列| |str*)|先頭がstrの文字列| |*str)|末尾がstrの文字列| |[a-z]*)|先頭がアルファベット小文字| |[!0-9]*)|先頭が数字以外の文字列| |[yY]|yかY| |???)|3文字の文字列| |*)|すべて| ==== case分 例1 ==== 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文 例2 キーボードからの入力で処理を分ける ==== 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文 ===== select文はbashで追加となった制御文です。\\ 項目をリストし、番号を選んで処理させるというメニュー形式の対話的な画面が簡単に作れます。\\ case文でも同じようなメニュー画面を作成することもできますが、大掛かりなスクリプトになってしまいます。\\ select文を使うとメニュー画面を簡単に作成できるメリットがあります。 ==== 構文 ==== select variable in menulists do commands done ==== select分 例1 ==== ※select文の場合は必ずbashを指定しなければなりません。\\  ×#!/bin/sh ○#!/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. ===== continueコマンド ===== for文やwhile文などの処理を途中で中断し、処理をループの先頭に戻すコマンドがcontinueです。\\ 書式もbreakコマンドと同じで、いくつ前のループ文の先頭へ戻るかを引数で渡せます。 ==== 構文 ==== continue 実行を継続したいループまでの深さ ==== continueコマンド 例1 ==== 以下のようにfor文が3つのネストになっている場合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コマンド ===== for文やwhile文から強制的に抜けるコマンドがbreakコマンドです。\\ もちろんselect文やuntil文からも抜け出せます。\\ continueコマンドがループの先頭に戻るのに対し、breakコマンドはループを抜けます。\\ breakコマンドは、引数がないとループ文を1つだけ抜けます。\\ ネストした複数のループを一挙に抜けたいときは、いくつのループを抜けるかという数を引数として指します。\\ ※引数に指定した数値の方がループのネストより多かったときは一番上位のループを抜けますが、エラーにはなりません。 ==== 構文 ==== break 抜けたいループの深さ ==== breakコマンド 例1 ==== 以下のようにfor文が3つのネストになっている場合3を指定すると全てのループから抜けます。 #!/bin/sh for a do for b do for c do break 3 done done done {{tag>bash:syntax bash}}