シェルスクリプトでの制御文

このページでは、シェルスクリプトの基本で 学習した内容を踏まえて、制御文を学習し、 より複雑な処理ができるようになりましょう。制御文とは難しい言葉に 感じるかも知れませんが、

「ある条件の時にはAという処理を行う」
「条件にあてはまらない時にはBという処理を行う」

というような、特定の条件に合致するか判定し、 その結果異なる処理を行う場合に、制御文が利用されます。 順を追って練習してみましょう。

引数

まず引数(ひきすう)という概念を理解してもらいます。 「emacs」で「test2-1.sh」というファイルを作成しますが、 コマンドラインで下記のように入力してください。

bash-2.05$ emacs test2-1.sh

emacsというエディタが立ち上がりますので、下記の内容を書いてください。 emacsの基本的な使い方は 大見先生のページに示されていますので参照してください。 保存ができたら、emacsを終了してください。


#!/bin/bash

echo $@
echo $#
echo $0
echo $1

まだどのような内容か理解していないと思いますが、下記のようにchmodを 使用して、実行可能な形式にします。

bash-2.05$ chmod +x test2-1.sh
bash-2.05$ ls -l test2-1.sh
-rwxr-----    1 susaki   teacher        38  5月  7 23:56 test2-1.sh

「ls -l」の結果、実行可能な形式を示す「x」が表示されているか確認して 下さい。

実行するときは、

./シェルスクリプト名

のように、皆さんの環境設定では./を つけないと実行されないようになっていますので注意してください。 それでは下記のように実行してみましょう。赤い文字の部分を入力して Enterキーを押してください。

例1)
bash-2.05$ ./test2-1.sh

0
./test2-1.sh


例2)
bash-2.05$ ./test2-1.sh aaa bbbbb cc d e
aaa bbbbb cc d e
5
./test2-1.sh
aaa

例1)では、./test2-1.shと打ち込んだだけです。 一方、例2)では、./test2-1.sh aaa bbbbb cc d eと、空白を区切りにして様々な文字列を入力しました。

ここで、「test2-1.sh」のスクリプトの中身を説明します。「test2-1.sh」の中で echoコマンドで表示させていたのは、下記のようなものです。

変数 意味
$@ 全引数(空白区切り)
$# 引数の数
$0 コマンド名
$1 1番目の引数

引数とは、上記の例1、2では「./ test2-1.sh」より後に入力した文字列のことです。例1では、何も入力しなかった ので、全引数は空白行で表され、引数の数も0となりました。$0はコマンドその ものを表示しますので、「./test2-1.sh」が表示されました。

一方、例2では、引数を「aaa」「bbbbb」「cc」「d」「e」と5つ指定しました。 全引数として「aaa bbbbb cc d e」が表示され、引数の数は5、コマンド名は 「./test2-1.sh」、1番目の引数として「aaa」が表示されたわけです。

if文による条件分岐

まずは、「test2-2.sh」というファイル名で、下記の内容を保存しましょう。

#!/bin/bash

hour=`date +%H`

if [ "$hour" -lt 12 ]
then
    echo "今は午前です"
else
    echo "今は午後です"
fi

この中身を説明しますと、

#!/bin/bash

hour=`date +%H`          <- 現在の時刻を変数hourに代入

if [ "$hour" -lt 12 ]      <- 変数hourが12より小さいか比較
then
    echo "今は午前です"  <- 変数hourが12より小さければ実行
else
    echo "今は午後です"  <- 変数hourが12より小さくなければ実行
fi

つまり、変数hourと12を比較して、12より小さければ"今は午前です"という メッセージを、そうでなければ"今は午後です"というメッセージを表示させる、 という内容です。

注意:変数を[ ]の判定式で使用する際には、 " "でくくる必要があるので注意せよ。(変数の中身が空の場合、 " "でくくっていないと、比較演算ができないというエラーが表示 されるため)

上記の例では、-ltという記号を使いました。 これは「左側の数字が右側の数字より小さければ真」という比較を行う 演算子です。比較を行う場合、文字列と数字とで使用する記号が異なりますので、 注意しましょう。

文字列
= 等しい
!= 等しくない
数字
-eq 等し[ (equal to)
-ne 等しくな[ (not equal to)
-gt より大き[ (greater than)
-ge 以上 (greater than and equal to)
-lt より小さ[ (less than)
-le 以[ (less than and equal to)

if文の練習問題

  1. 下記の内容を、「test2-2-1.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。 ちなみに、readを利用することで、キーボードからの入力を変数に代入する ことができる。
    #!/bin/bash
    
    echo "好きな整数を入れてください"
    read num
    
    if [ "$num" -lt 100 ]
    then
        echo "$numは100未満です"
    elif [ "$num" -lt 1000 ]
    then
        echo "$numは100以上1000未満です"
    else
        echo "$numは1000以上です"
    fi
    
    (実行結果)
    bash-2.05$ ./test2-2-1.sh
    好きな整数を入れてください
    -9
    -9は100未満です
    bash-2.05$ ./test2-2-1.sh
    好きな整数を入れてください
    120
    120は100以上1000未満です
    bash-2.05$ ./test2-2-1.sh
    好きな整数を入れてください
    1000
    1000は1000以上です
    
  2. 下記の内容を、「test2-2-2.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。
    #!/bin/bash
    
    echo "3回目の小テストの点数(0から20までの数字)を入れてください"
    read num
    
    if [ "$num" -ge 0 -a "$num" -lt 7 ]
    then
        echo "もっと勉強しましょう。"
    elif [ "$num" -ge 7 -a "$num" -lt 15 ]
    then
        echo "まずまずです。"
    elif [ "$num" -ge 15 -a "$num" -le 20 ]
    then
        echo "よく頑張りました"
    else
        echo "入力した数字は0から20までの数字ではありません"
    fi
    
    (実行結果)
    bash-2.05$ ./test2-2-2.sh
    3回目の小テストの点数(0から20までの数字)を入れてください
    0
    もっと勉強しましょう。
    bash-2.05$ ./test2-2-2.sh
    3回目の小テストの点数(0から20までの数字)を入れてください
    4
    もっと勉強しましょう。
    bash-2.05$ ./test2-2-2.sh
    3回目の小テストの点数(0から20までの数字)を入れてください
    19
    よく頑張りました
    bash-2.05$ ./test2-2-2.sh
    3回目の小テストの点数(0から20までの数字)を入れてください
    21
    入力した数字は0から20までの数字ではありません
    
  3. 下記の内容を、「test2-2-3.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。
    #!/bin/bash
    
    echo "リテラシーの先生の名前をローマ字で入力してください"
    read name
    
    if [ "$name" = "suzuki" -o "$name" = "doi" ]
    then
        echo "あなたはAクラスの学生です"
    elif [ "$name" = "susaki" -o "$name" = "ohshiro" -o "$name" = "oshiro" ]
    then
        echo "あなたはBクラスの学生です"
    elif [ "$name" = "yamaga" -o "$name" = "shinohara" ]
    then
        echo "あなたはCクラスの学生です"
    else
        echo "入力ミスか、入力した名前の先生はいません。"
    fi
    
    (実行結果)
    bash-2.05$ ./test2-2-3.sh
    リテラシーの先生の名前をローマ字で入力してください
    oshiro
    あなたはBクラスの学生です
    bash-2.05$ ./test2-2-3.sh
    リテラシーの先生の名前をローマ字で入力してください
    ohshiro
    あなたはBクラスの学生です
    bash-2.05$ ./test2-2-3.sh
    リテラシーの先生の名前をローマ字で入力してください
    yamaga
    あなたはCクラスの学生です
    bash-2.05$ ./test2-2-3.sh
    リテラシーの先生の名前をローマ字で入力してください
    sato
    入力ミスか、入力した名前の先生はいません。
    bash-2.05$ ./test2-2-3.sh
    リテラシーの先生の名前をローマ字で入力してください
    doi
    あなたはAクラスの学生です
    
  4. 下記の内容を、「test2-2-4.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。 「test2-2-3.sh」はreadを用いて変数に入力データを代入したのに対して、 「test2-2-4.sh」では、実行時の引数をそのまま利用している。
    #!/bin/bash
    
    if [ "$1" = "" ]
    then
        echo "先生の名前を引数として入力してください。"
    elif [ "$1" = "suzuki" -o "$1" = "doi" ]
    then
        echo "あなたはAクラスの学生です"
    elif [ "$1" = "susaki" -o "$1" = "ohshiro" -o "$1" = "oshiro" ]
    then
        echo "あなたはBクラスの学生です"
    elif [ "$1" = "yamaga" -o "$1" = "shinohara" ]
    then
        echo "あなたはCクラスの学生です"
    else
        echo "入力ミスか、入力した名前の先生はいません。"
    fi
    
    (実行結果)
    bash-2.05$ ./test2-2-4.sh
    先生の名前を引数として入力してください。
    bash-2.05$ ./test2-2-4.sh ohshiro
    あなたはBクラスの学生です
    bash-2.05$ ./test2-2-4.sh suzuki
    あなたはAクラスの学生です
    bash-2.05$ ./test2-2-4.sh tanaka
    入力ミスか、入力した名前の先生はいません。
    

while文による繰り返し

ここではwhileを使った繰り返しについて学習します。このページの冒頭で 説明した引数を利用した処理を 紹介します。前回と同様、 「emacs」で「test2-3.sh」というファイルを作成します。下記の内容を 記述してください。

#!/bin/bash

while [ "$1" != "" ]
do
    echo $1
    shift
done

保存したら、chmodを使用して「test2-3.sh」を 実行形式に変更し、下記の赤字で表示されているように入力して 実行してみましょう。

bash-2.05$ ./test2-3.sh aaa bbbbb cc d e
aaa
bbbbb
cc
d
e

スクリプトの中身を見ると、

#!/bin/bash

while [ "$1" != "" ]   <- $1(1番目の引数)が空白でない間、
do                                              処理を繰り返す
    echo $1            <- $1の表示
    shift              <- 引数のシフト($2が$1へ代入される)
done

ということで、すべての引数が表示されることになります。

つまり、while文では、

while [ 条件式 ] 
do
    処理
done

という形式を取り、条件式が満たされる間、doとdoneで囲まれた処理を繰り返し ます。

while文の練習問題

  1. 下記の内容を、「test2-3-1.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。
    #!/bin/bash
    
    num=3
    while [ "$num" -lt 10 ]
    do
        echo '$num'"の値は$num"
        num=`expr $num + 1`
    done
    
    (実行結果)
    bash-2.05$ ./test2-3-1.sh
    $numの値は3
    $numの値は4
    $numの値は5
    $numの値は6
    $numの値は7
    $numの値は8
    $numの値は9
    
  2. 下記の内容を、「test2-3-2.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。 「test2-3-1.sh」では、初期値として3が与えられたnumの値が10よりも小さい間、 do doneで囲まれた命令を繰り返したが、 「test2-3-2.sh」では、実行時の引数を変数numに代入して処理している。
    #!/bin/bash
    
    num=$1
    while [ "$num" -lt 10 ]
    do
        echo '$num'"の値は$num"
        num=`expr $num + 1`
    done
    
    (実行結果)
    bash-2.05$ ./test2-3-2.sh 2
    $numの値は2
    $numの値は3
    $numの値は4
    $numの値は5
    $numの値は6
    $numの値は7
    $numの値は8
    $numの値は9
    bash-2.05$ ./test2-3-2.sh 8
    $numの値は8
    $numの値は9
    bash-2.05$ ./test2-3-2.sh 12
    bash-2.05$
    
  3. 下記のスクリプトは、乱数で決定した値に対し、入力した値が大きいか小さいか 表示し、最終的に乱数の値を推定するものである。推定値と乱数の値が 一致した場合に、breakでwhile文のループから脱出する。 下記の内容を、「test2-3-4.sh」というファイルに記述せよ。 その後、実行し動作確認せよ。
    #!/bin/bash
    
    num=$RANDOM
    
    echo "***** ある隠された値を当ててくださ[ *****"
    
    while true
    do
        echo "0から32767までの数字を入力してください"
        read x
        if [ $x -gt $num ]
        then
            echo "もっと小さいですよ"
        elif [ $x -lt $num ]
        then
            echo "もっと大きいですよ"
        else
            echo "ずばり当たりです!"
            break
        fi
    done
    
    (実行結果)
    bash-2.05$ ./test2-3-3.sh
    ***** ある隠された値を当ててくださ[ *****
    0から32767までの数字を入力してください
    10000
    もっと大きいですよ
    0から32767までの数字を入力してください
    20000
    もっと大きいですよ
    0から32767までの数字を入力してください
    30000
    もっと小さいですよ
    (省略)
    0から32767までの数字を入力してください
    23500
    もっと小さいですよ
    0から32767までの数字を入力してください
    23300
    もっと大きいですよ
    0から32767までの数字を入力してください
    23490
    もっと大きいですよ
    0から32767までの数字を入力してください
    23495
    もっと大きいですよ
    0から32767までの数字を入力してください
    23498
    ずばり当たりです!
    

[1.シェルスクリプトの基本] [3.シェルスクリプトの事例1] [4.シェルスクリプトの事例2]
[UNIXコマンドのページへ戻る] [須崎純一のページへ戻る]
須崎純一 京都大学大学 工学研究科都市環境工学専攻 環境情報学講座