Lesson 13

シェルスクリプトを利用してプログラミングをしてみよう

Lesson 13 Chapter 1
はじめに

このレッスンではシェルスクリプトと呼ばれる、シェルが理解できる命令文を集めたプログラムを実際に書いて、出力結果を確認するところまで学んでいきます。 これらをマスターすることで、普段GUIにて行っている操作などをコマンドで行ったり、システムの細かい設定などをすることが出来るようになります。まずはシェルの概念から学んでいきましょう。

シェルとは

シェルとは、OSの中核となるシステム(カーネル)とユーザーの間で命令のやり取りをサポートするものです。主にユーザーからの入力を解釈し、コンピューターの機能を実行するためのコマンドを受け取ります。 また、シェルにはいくつか種類がありますが、最も一般的なものはUNIXシェルで```Bash```,```Zsh```,```Ksh```などがあります。

シェルスクリプトとは

シェルスクリプトとはシェルが解釈できるコマンドを記述したスクリプトファイルのことです。シェルスクリプトを実行すると、ファイル記述されたコマンドが上から順番に実行されます。 シェルスクリプトを使用することで、複数のコマンドをまとめて実行することができたり、複数のコマンドを繰り返し実行することが出来るといったメリットがあります。

シェルスクリプトの実行方法はいくつかありますが、基本的には以下のコマンドで実行できます。

$ ./[ファイル(シェルスクリプト)名]

では実際に、具体的なシェルスクリプトの記述方法や実行方法について学習していきましょう。

Lesson 13 Chapter 2
パラメータを受け取ってみよう

シェルスクリプト実行時にパラメータ(引数)と呼ばれる値を、シェルスクリプト自身に渡して実行することが出来ます。 例として、sample.shというシェルスクリプトファイルに"Hello"という文字列をパラメータとして渡して実行するコマンドは以下の通りです。

$ ./sample.sh Hello

また、2つ以上のパラメータを同時に渡すことも可能です。

$ ./sample.sh Hello Bye 999

ここでは"Hello", "Bye", "999"をそれぞれ半角スペースで区切ることで、3つのパラメータを渡していることが分かります。 次のチャプターでは、実際に渡したパラメータをシェルスクリプトで利用するための記述について学んでいきます。

Lesson 13 Chapter 3
標準出力でシェルスクリプトの実行結果を見てみよう

標準出力とは、コンピューターで実行されるプログラムやコマンドが出力する、標準的な出力先のことです。通常、コマンドを実行している環境であるコンソールやターミナルウィンドウに出力されます。 シェルスクリプトではecho(エコー)コマンドを使用することで標準出力を利用して任意のテキストをコンソールに表示することが出来ます。

以下は"Hello World"というテキストを標準出力するシェルスクリプトです。

#!/bin/bash

echo "Hello World"

では次に、受け取ったパラメータを標準出力するhello.shというシェルスクリプトを書いていきます。

#!/bin/bash

echo $1

このように1番目に渡されたパラメータは$1と記述することで呼び出すことが出来ます。また、$2とした場合2番目のパラメータを呼び出すことになります。 このシェルスクリプトに"Hello"というパラメータを渡して実行すると以下の様になります。

$ ./hello.sh Hello
Hello

こうして、パラメータとして渡した"Hello"という文字列が出力結果として表示することが出来ます。

Lesson 13 Chapter 4
変数を使用して値を保存してみよう

変数とは、プログラムやスクリプトで使用される、値(データ)を保存するための箱のような物です。パラメータをスクリプト内で使用する際に記述した$1なども変数と言えます。 シェルスクリプト内で変数を定義するには以下のような記述をします。

変数名=値

例として"Hello World!"といった文字列をtextという変数に格納してみます。

text="Hello World!"

このように変数定義をすることで以後、$textという記述をするだけでHello World!という文字列を呼び出すことが出来ます。 まとめると、変数を利用した"Hello World!"を標準出力するシェルスクリプトは以下のようになります。

#!/bin/bash

text="Hello World!"
echo $text

これが変数の基本的な使用方法となります。何度も頻出する値などは、変数を利用することで、その値に変化があった場合に変数定義の箇所のみを編集するだけで全体に反映されるといったメリットなどがあります。

Lesson 13 Chapter 5
シェルスクリプトの出力結果を保存してみよう

シェルスクリプトを実行し、その出力結果をテキストファイルなどに出力することが出来ます。コマンドは以下の通りです。

$ [コマンド(シェルスクリプト)] > [出力先のファイル名]

まずはシンプルな"Hello World!"を標準出力するだけのhello.shというシェルスクリプトを用意します。

#!/bin/bash

echo "Hello World!"

それでは上記スクリプトの標準出力をtest.txtというテキストファイルに向けて実行してみます。

$ ./hello.sh > test.txt

text.txtファイルを開くとHello World!という文字列が1行表示されます。 また、以下のように>を2つ重ねることで、標準出力を受け取る度にファイルに結果を追記する事もできます。

$ ./hello.sh >> test.txt

こうすることで、上記コマンドを実行する度にtest.txtファイルに"Hello World!"という文字列が1行ずつ追加されていきます。

Lesson 13 Chapter 6
制御構文を使って特殊な処理の流れを作ってみよう

基本的にシェルスクリプトは、上から下へ順番にコマンドが処理されて行きます。 そこで、このチャプターでは特定の条件によって処理の流れを制御するコマンドである「制御構文」について学習していきます。 ここではif(イフ)文, while(ホワイル)文, for(フォー)文という3つの制御構文を紹介します。

if文

if文では特定の条件が成立した際に実行する処理を記述します。条件式に当てはまる場合を真(True)と呼び、当てはまらない場合を偽(False)と呼びます。 基本的な書き方は以下の通りです。

  • ifで始まりfiで終わる。
  • ifの右隣に条件式を記述する。
  • 条件式は[ ]で囲むこと。(条件式と括弧の間には半角スペースを入れる)
  • 条件式が真の場合の処理はif文直下のthenの下に記述する。
  • 条件式が偽の場合の処理はelseの下に記述する。
if [ 条件式 ];
then
  処理1
else
  処理2
fi

条件式では主に「数値の比較」と「文字列の比較」があります。それぞれの条件式の書き方は以下のものがあります。

数値の比較

条件式 説明
数値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以下であれば真

文字列の比較

条件式 説明
文字列1 = 文字列2 文字列1と文字列2が等しければ真
文字列1 != 文字列2 文字列1と文字列2が等しくなければ真
-n 文字列 文字列の長さ(文字数)が1以上であれば真
-z 文字列 文字列の長さ(文字数)が0であれば真

それでは実際にif文を利用して、変数の値によって標準出力分を切り分けるシェルスクリプトを書いていきます。

#!/bin/bash

text="Hello"

if [ $text = "Hello" ];
then
  echo "Hello World!"
else
  echo "Bye"
fi

このスクリプトはtext変数の値が"Hello"だった場合に Hello World!を出力し、それ以外の場合はByeを出力する処理となっています。 ここではtext変数の初期値に"Hello"という文字列を代入しているため、実行結果は Hello World!が出力されることになります。

また、elifを使うことで条件式を増やして処理の分岐を増やすことも出来ます。

#!/bin/bash

text="morning"

if [ $text = "Hello" ];
then
  echo "Hello World!"
elif [ $text = "morning" ];
then
  echo "Good morning!"
else
  echo "Bye"
fi

これは先程のスクリプトにelifによる条件分岐を増やしたものになります。 text変数の値が"morning"であった場合に Good morning!というテキストを出力する処理が追加されています。この時、elseの処理が実行される条件は text変数の値が"Hello"でも"morning"でも無い場合ということになります。

while文

while文は条件文が真である間、記述した処理を繰り返します。条件式はif文と同じように書くことが出来ます。

while [ 条件式 ]
do
  処理
done

count変数の値を処理1回ごとに数値として+1していき、countの値が5未満でなくなった時にループ処理を終了するスクリプトを書いていきます。

#!/bin/bash

count=0

while [ $count -lt 5 ]
do
  count=$((count + 1))
  echo "Good morning!"
done

count変数の初期値は0であるため、このwhile文の処理は5回行われるということになります。 また、$(( ))count変数を数値データとして扱うための記法になります。

for文

for文では、変数にデータリストの各要素が左から順番に代入され、処理が実行されます。データリストにある複数の値は半角スペース区切りで定義します。データリストから全ての値を取り出して処理されるとループが終了します。

for 変数名 in 変数に代入する値のリスト
do
  処理
done

では、データリストに3つの文字列を定義して順に出力するスクリプトを書いていきます。

#!/bin/bash

for text in "nice" "great" "excellent"
do
  echo $text
done

実際の実行結果は以下のようになります。

$ ./test.sh
nice
great
excellent

データリストに定義した各文字列が1行ずつ標準出力されていることが確認できました。

Lesson 13 Chapter 7
利用者からの入力を受け取る

シェルスクリプトを実行と同時にパラメータとして入力値を与えることは学びましたが実行中に適時、ユーザーからの入力を受け取ることも出来ます。 このチャプターでは、標準入力からの入力を受け付けるread(リード)コマンドについて学習していきます。基本的なコマンドの書き方は以下の通りです。

read [変数名]

では実際に、キーボードから名前を入力し、ウェルカムメッセージを標準出力するスクリプトを書いていきます。

#!/bin/bash

read name
echo "$name さん、こんにちは"

上記スクリプトを実行すると、コンソールのカーソルが点滅し「入力待ち状態」となります。この状態で任意の文字列を入力し、エンターキーを押すと標準入力が完了します。

$ ./test.sh
太郎
太郎 さん、こんにちは

このように入力した値(名前)と" さん、こんにちは"という文字列を連結して出力されていることが確認できます。

select文

select文は、複数の選択肢を表示し、ユーザーからの選択を待ち受けることが出来ます。基本的な書き方は以下の通りです。

select 変数名 in 選択肢となるデータリスト
do
  処理
done

まず最初に、先程のfor文を使用したスクリプトをselect文へ書き換えてみましょう。

#!/bin/bash

select text in "nice" "great" "excellent"
do
  echo $text
done

変更箇所としては、forの記述をselectへ変更しました。これを実行してみます。

$ ./test.sh
1) nice
2) great
3) excellent
#? 

すると、1, 2, 3という選択肢にデータリストとして渡した値が表示されている事が確認できます。さらに、#?という表示があり入力待ち状態になっています。
試しに2を入力すると、

$ ./test.sh
1) nice
2) great
3) excellent
#? 2
great
#? 

選択肢2に該当するgreatという文字列が出力され、次の入力待ち状態になっていることが確認できます。 処理の流れとしては、選択肢の番号を入力すると、その番号に対応した選択肢の値がtext変数に格納されて処理が実行されるといった流れになります。

また、今の状態では永遠に処理のループを繰り返してしまいますがbreakを利用することでループを終了することも出来ます。

#!/bin/bash

select text in "nice" "great" "excellent"
do
  echo $text
  break
done

こうすることで、選択肢の入力とその後の処理が行われたあとにbreakが実行されてループを終了することが出来ます。

Lesson 13 Chapter 8
関数

関数とは、特定の処理をまとめたものであり、複数回使用することができるようにするためのものです。 一度関数として定義した処理は、その関数を呼び出すだけで関数に記述された処理を行うことが可能です。 シェルスクリプトでは、関数を以下のように定義します。

#!/bin/bash

function 関数名 () {
    処理
}

例として"Hello World"を出力する処理を関数に定義し、それを呼び出すスクリプトを書いていきます。

#!/bin/bash

function sayHello () {
  echo "Hello World!"
}

sayHello

このように関数名を記述するだけで関数を呼び出すことが出来ます。また、パラメータと同じように関数に対して引数を渡すことも出来ます。

#!/bin/bash

function sayHello () {
  echo "$1 さん こんにちは!"
}

sayHello "太郎"

引数を渡す際は関数呼び出しの隣に半角スペースを開けて値を記述します。ここでは"太郎"という文字列を sayHello関数に渡しており、受け取った引数と" さん こんにちは!"を連結して出力しています。 複雑なシェルスクリプトを書いていく上で、何度も頻出する処理は関数としてまとめることで、読みやすいスクリプトになるというメリットがあります。

ここまでお疲れさまでした。 このレッスンでは主に「シェルスクリプトの概要」「シェルスクリプトの書き方」などについて学んできました。 シェルスクリプトを使いこなすことで、効率的で可読性の高いプログラムを記述することができ、ちょっとした業務の自動化や効率化を図ることが出来ます。