ドットインストール様の動画を拝聴し、ShellScriptを学習しました。
その際のメモです。
動画の方はこちらから↓
http://dotinstall.com/lessons/basic_shellscript
1 シェルスクリプトとは?
シェルスクリプトは、オペレーティングシステムのシェルまたはコマンドラインインタプリタ向けに書かれたスクリプトである。
シェルスクリプト - Wikipediaより
シェル (shell) はオペレーティングシステム (OS) のユーザーのためにインタフェースを提供するソフトウェアであり、カーネルのサービスへのアクセスを提供する。
シェル - Wikipediaより
OSから情報を引き出したり、操作したりするスクリプトのこと。
2 はじめてのシェルスクリプト
今回、私はVagrant(CentOS)にて学習しました。
以下のコマンドで、その環境にて使用されているシェルを確認します。
echo $SHELL
# /bin/bash
私の環境では、bash
が使用されていました。
学習用ディレクトリ内にhello.sh
を作成し、文頭に以下の1行を書きます。
これは、シェルスクリプトを書く際の決まり文句となる。
!#/bin/bash
Helloという文字列を出力します。
# 文字列の出力
echo "Hello"
# 正常終了した場合、0を返す
exit 0
実行の際には、ファイルのあるディレクトリで以下のコマンドを入力する
./hello.sh
# Hello
3 変数(文字列)
# =前後にはスペースを入れない
s="Hello"
echo $s # Hello
echo "$s" # Hello
echo "${s}" # Hello
echo $s$s # HelloHello
echo "$s $s" # Hello Hello
echo '$s' # $s シングルクォーテーションだと展開されない
4 数値演算
$x=10
echo `expr $x + 2` # 12
# バッククォートで囲われたコマンドが実行される
# expr、演算子の前後にはスペースを入れる
ちなみにexpr
は整数計算を行う際に利用されるシェルスクリプトのコマンドです。
整数計算を行う「expr」
#5 四則演算
演算子は以下の通りです。
# 引き算: +
# 引き算: -
# 割り算: /
# 掛け算: \*
# 掛け算のみ、バックスラッシュでエスケープさせる。エスケープしないとシンタックスエラーとなる
また、数学でもそうですが、先に計算したい足し算、引き算には()
でくくると思います。
その場合は、以下のように書きます。
シェルスクリプトでは、()
はエスケープさせないといけません。
# (x + 2) * 5 を計算したい
echo \( $x + 2 \) \* 5
変数の定義時に、readonly
をつけると、上書きが効かなくなります。
大事な変数にはつけましょう。
readonly FILE_NAME=“test"
FILE_NAME=“test2”
# -bash: FIRST_NAME: readonly variable
# -> 上書きできないよ、というエラー
#6〜7 配列
a=(2 4 6) # 配列の定義
# 1番目の配列を取り出す
echo $a # 2
# 2番目の配列を取り出す([]内を変更すれば、任意の順番の配列を取得できる)
echo $a{[1]} # 4
# エラーの例({}をつけない場合)
# $aは配列の1番目として読み込まれ、[1]は文字列と認識されてしまう
echo $a[1] # 2[1]
# 全ての配列を出力
echo {$a[@]} # 2 4 6
# 配列の数をカウント
echo ${#a[@]} # 3
配列を使う上で、下記のようなことも覚えておく必要があります。
a=(2 4 6)
# 配列の上書き
a[2]=10 # 配列の3番目を10に上書きする
echo ${a[@]} # 2 4 10
# 配列の要素の追加
a+=(20 30) # 配列の要素を追加
echo ${a[@]} # 2 4 10 20 30
また、配列の応用例で、UNIXコマンドのdate
関数を使い、
1週間の日付を配列で持ってきて、指定した位置の日付を出力させます。
# 日付を取得
d=(`date`)
# 4番目の値を取得(0が日曜日)
echo ${d[3]}
# 今週の水曜日が出力される
#8〜9 条件式
test
コマンドは、与えた条件が正しいかどうか試験してくれます。
([ ]
で囲うことで省略も可能)
正常終了すると0
が、エラーが起こると1
を返します。
test 1 -eq 2; echo $? 1が返る
test 1 -eq 1; echo $? 0が返る
$?
は直前にやった条件式の結果を返す標準変数です。
比較演算子や論理演算子については、下記リンクに詳しく述っています。
if文とtestコマンド
10~11 if文で条件分岐
if文は以下のように書きます。
# $xが60より大きかったら、OK!と出力
x=70
if test $x -gt 60
then
echo "OK!"
fi
# OK!
また、test
は以下のように[``]
で書き換えることも可能です。
# $xが60より大きかったら、OK!と出力
x=70
if [ $x -gt 60 ]; then
echo "OK!"
fi
# OK!
複数条件を記載する場合は、他の言語のelse
、elseif`にあたるものを利用します。
# $xが60より大きかったら、OK!と出力
# $xが60以下で、40より大きければsoso...と出力
# $xが上記以外であればng...と出力
x=20
if [ $x -gt 60 ]; then
echo "OK!"
elif [ $x -gt 40 ]; then
echo "soso..."
else
echo "ng..."
fi
# ng...
動画内で説明はありませんでしたが、UNIXコマンドのwhich
は、指定したコマンドのパス(場所)を検索してフルパスで表示します。
今回利用した[
をwhich [
で検索すると、私の場合は/usr/bin/[
と出力されます。
つまり、/usr/bin/
以下にこのコマンドがあるということになります。
12 case文で条件分岐
case文は以下のように書きます。
# $xが60より大きかったら、OK!と出力
signal="red"
case $signal in
"red") # redの場合
echo "stop!"
;;
"yellow") # yellowの場合
echo "caution!"
;;
"green") # greenの場合
echo "go!"
;;
*) # その他の場合
echo "..."
;;
esac
# stop!
13 while文でループ処理
while文は以下のように書きます。
# 1から10まで出力
i=0
while [$i -lt 10 ]
do
i='expr $i + 1`
echo $i
done
また、if文と併用してcontinue
、break
も使用できます。
while
の後、条件文の場所を:(ヌルコマンド)
にすると無限ループが発生します。
そちらをcontinue
、break
も利用して下記のようにします。
i=0
while : #無限ループ開始
do
i='expr $i + 1`
# $iが3であればスキップ
if [$i -eq 3 ]; then
continue
fi
# $iが10より大きければループを抜ける
if [$i -gt 10 ]; then
break
fi
echo $i
done
14 for文
例えば、1〜5を順番に出力したいときは以下のように書きます。
for i in 1 2 3 4 5
do
echo $i
done
do
とdone
によって囲われた部分を繰り返します。
また、条件の部分で、配列を使用できます。
a=(1 2 3 4 5)
for i in ${a[@]} # 配列を全て展開
do
echo $i
done
そもそも条件文をいちいち書くのが面倒な場合は、seq
が使えます。
シェルスクリプトで指定回数ループ処理
seq
は第1引数から第2引数までの値を出力してくれます。
第3引数を指定すれば、出力間隔も指定できます(デフォルトは1)
for i in `seq 1 100`
do
echo $i
done
# 1〜100まで出力される
また、while文と同様に、continue
、break
も使用できます。
15 コマンド引数を渡す
コマンドからファイルに対して引数を渡すとします。
その場合、$0
、$1`という特殊な変数を与えることで、引数をプログラムん与えることができます。
以下のファイルを用意します。
# プログラム自身の名前(ファイル名)
echo $0
# 1番目の引数を出力
echo $1
# 2番目の引数を出力
echo $2
# 全ての引数を出力
echo $@
# 全ての引数の数を出力
echo $#
そして、コマンドラインから以下のように入力します。
$ ./hello.sh a b
結果はこちらになると思います。
./hello.sh # $0
a # $1
b # $2
a b # $@
2 # $#
ちなみに、10以上の引数を使う場合には{}
をつけて変数を用意します。
echo ${10}
16 ユーザーからの入力を受け付ける
例えば、ユーザーから特定の文字を入力されないと、延々と次に進めないようなプログラムを作るとします。
while :
do
read key
echo "you pressed $key"
if [ $key = "end" ]; then
break
fi
done
これを実行すると、まず何も起こりませんが、ここで適当なキーを打ち込んでみてください。
例えば、a
を打ち込みます。
you pressed a
上のように表示されます。
適当な文字列を打ち込んでも同様な状態になると思います。
ここで、if文で指定したend
と押すと、終了します。
read
コマンドを利用しましたが、これは入力された文字列を指定された変数に格納する標準コマンドです。
今回はkey
を変数として指定しているため、入力された文字列を出力できます。
readコマンド
また、他にもselect
というコマンドもあります。
select
はfor
文のようなループ系のコマンドですが、用意された配列の中からユーザーに選択してもらい、その文字列を変数に格納します。
select option in var opt home exit
do
echo "you pressed $option"
break
done
これを実行すると、以下のように表示されると思います。
1) var
2) opt
3) home
4) exit
#?
ここで、キーボードで1
を押すと、
you pressed var
2
を押すと、
you pressed opt
と出力されます。
これにif文などを組み合わせれば、このボタンでこの処理、このボタンでこの処理、とできるようです。
制御構文 FOR / SELECT
17 別ファイルの内容を読み込む
以下のテキストファイルを用意します。
yesterday
today
tomorrow
このファイルを読み込んで、1行ずつ出力させます。
それでは、シェルスクリプトのファイルに以下のように書きます。
# while readで与えられたファイルを1行ずつ読み込む
while read line
do
echo $line
# $1は第1引数のための変数
done <$1
そしてコマンドラインに戻り、以下のように入力します。
$ ./hello.sh data.txt
結果は、
yesterday
today
tomorrow
これは、第1引数で読み込むファイル名を指定して、$1
に格納します。
while read
で$1
に入っている、つまりdata.txt
の行数まで繰り返し、文字列を出力します。
こちらはよく利用するようで、いろいろなパターンがあるようです。
シェルスクリプトでよく使われる while read line 4パターン
18 関数
関数は以下のように作成します。
(function
は省略可能)
function hello() {
echo "hello"
}
# 関数の呼び出し
hello
これで、./hello.sh
を呼び出すと、hello
と出力されます。
例えば、引数を利用したいときは、$1
、$2
などの標準変数を利用して、以下のように書き換えます。
function hello() {
echo "hello $1 and $2"
}
# 関数の呼び出し
hello Mike Tom
関数内で利用する変数ですが、シェルスクリプトでは関数内で宣言しても、関数外で使用できます。
function hello() {
echo "hello $1 and $2"
i=5
echo $i
}
# 関数の呼び出し
hello Mike Tom
echo $i
これは、関数内、関数外両方ともecho
で出力されます。
関数内のみで使用したい場合は、変数宣言時にlocal
をつけて、local i=5
とします。