サーバエンジニアであっても、プログラマでも使えた方が良い技術がシェルスクリプトです。
サーバエンジニアであれば処理の自動化や作業効率化のツールをサーバ上で作成できます。
また、プログラマであればわざわざアプリを作成しなくても、インタプリタ型で手軽にプログラムを作成できます。
シェルスクリプトが書けるほうが仕事の幅は広いです。
特にインフラエンジニアでは顕著ですが、スクリプトの作成を求められる事も多いです。
転職の面談でも頻繁に質問されます。
他にもPerlやRuby、Pythonのうち2つくらいは使える事が望ましいです。
今回はシェルスクリプトの基礎と構文を紹介していきます。
Perlの学習ではこちらの記事で書籍を紹介しています。
シェルスクリプトの書籍も紹介していますが、それは最後にリンクしたいと思います。
ではさっそくですが書いていきます。
コーディング前の基礎知識
変数の代入
プログラミングでもそうですが、変数を利用する事で利便性が向上します。
基礎的な使い方として、まずは情報を取得して変数へ格納します。
#!/bin/bash TODAY=`date +%Y%m%d` echo $TODAY
このように、TODAYという変数に対して、dateコマンドの結果を格納します。
では実行してみます。
[root@localhost ~]# chmod 755 test.sh [root@localhost ~]# ./test.sh 20180225
このように、echoコマンドで変数TODAYを表示すると日付が表示されます。
これは正常に変数に値が格納され、正常に情報を処理できていますね。
dateコマンドで日付を秒単位まで取得して、ログを出力したり処理の時間を図る事は多いので基礎的な知識として覚えておきましょう。
デバッグのための記述
シェルスクリプトをそのまま実行していても、エラーになった時の切り分けが必要です。
普通に実行していると、構文を見直す事が必要ですがコマンドのエラーや処理の内容を適切に確認する方法があります。
先ほどのスクリプトにset -xをシェルスクリプトの構文前に記述します。
また、touchコマンドでtest.txtファイルを作成し、rm -fコマンドで削除して、それからcatコマンドで削除されたファイルを参照しようとする処理を書きました。
#!/bin/bash set -x TODAY=`date +%Y%m%d` echo $TODAY touch test.txt rm -f test.txt cat test.txt
実行してみると以下のようになります。
[root@localhost ~]# ./test.sh ++ date +%Y%m%d + TODAY=20180225 + echo 20180225 20180225 + touch test.txt + rm -f test.txt + cat test.txt cat: test.txt: そのようなファイルやディレクトリはありません [root@localhost ~]#
正常に処理が完了している場合は、+で処理が展開されて変数に関しては格納された値が表示されています。
また、最後の存在しないファイルを参照しようとした処理はエラーが出力されています。
set -x文を記述して、ログにリダイレクトする事でスクリプトが正常に動作したかを確認できますね。
引数の使用
シェルスクリプトでは引数が使えます。
引数とは、コマンドのオプションと同様にスクリプトを実行するときにスペースを空けて文字列を入力して、それをスクリプトに値として引き渡すことです。
先ほどのスクリプトを以下のように修正します。
#!/bin/bash set -x TODAY=`date +%Y%m%d` echo $TODAY touch $1 rm -f $1 cat $1
$1は引数の1番目を表します。
さらにスペースを空けて文字を入力した場合は、$2となり$3……と数字が増えていきます。
ではこの状態で、aaa.txtと引数を入力して実行してみます。
[root@localhost ~]# ./test.sh aaaa.txt ++ date +%Y%m%d + TODAY=20180225 + echo 20180225 20180225 + touch aaaa.txt + rm -f aaaa.txt + cat aaaa.txt cat: aaaa.txt: そのようなファイルやディレクトリはありません
どうでしょう。
きちんとtouchコマンドでaaa.txtが作成され、削除されています。
このように、引数を利用してスクリプトを実行できるのも基礎知識なので覚えておきましょう。
基本的な構文
if文
if文はシェルスクリプトだけではなく、プログラミング言語や多言語でも基礎的な構文です。
そして一番、汎用的であります。
Windowsのバッチファイルなどでは、ifが使えないと値を変数に格納できないなど、色々と問題があったりしますので、絶対に覚えましょう。
では先ほどの基礎知識を踏まえて書いていきます。
#!/bin/bash set -x TODAY=`date +%Y%m%d` echo $TODAY if [ $1 -eq 10 ]; then echo "Input parameter is 10" else echo "Input parameter is not 10" fi
まず覚えるべきは、if文の終端子として、処理の終了にfiを記述する必要があります。
ここからここまでが処理です、という事を明示する必要があります。
そして、肝心のif文では、引数1が10であれば正常処理、10以外では例外(else)で処理します。
[root@localhost ~]# ./test.sh 10 20180225 Input parameter is 10 [root@localhost ~]# ./test.sh 11 20180225 Input parameter is not 10
実行結果ではデバッグの記述をコメントアウトしています。
記述の先頭に#を記述すれば可能です。
見ての通りですが、10を引数にした時と11を引数にしたときでechoコマンドの結果が違います。
正常にifで分岐した結果になります。
for文
次も基本的な構文である「for」について書きたいと思います。
UnixとLinuxで使えるオプションが違ったりするので、環境を変えてシェルスクリプトを実行する際は注意が必要です。
今回はLinuxを利用します。
以下の「test2.sh」ファイルを新しく作成します。
#!/bin/bash #set -x TODAY=`date +%Y%m%d` #echo $TODAY for i in `seq 1 10` do echo $i done exit
これは「seq」オプションを使い、10回ループさせる処理です。
もちろん、10の部分を引数にしてシェルスクリプトを実行する際にループ回数を指定するなど出来ます。
では実行してみましょう。
[root@localhost ~]# ./test2.sh 1 2 3 4 5 6 7 8 9 10
echoコマンドで変数iを出力しているので、ループ回数分の数字が出力されています。
for文の基本的な構文は以下になります。
シェルスクリプトではこのように記述します。
またワンライナーという技法で、シェルスクリプトにせずにコマンドで実行する場合は書く文を「;」で連結します。
[root@localhost ~]# for i in `seq 1 10` ; do echo $i ; done 1 2 3 4 5 6 7 8 9 10 [root@localhost ~]#
このようにシェルスクリプトだけではなくコマンドとしても応用できます。
単純なループ処理ではforを使うのがベーシックです。
while文
while文はファイル読み込みなどで便利ですが、無限ループを引き起こす原因になってしまう事があるので使い方には注意です。
ではまた「test3.sh」を作成して実行してみます。
[root@localhost ~]# cat test3.sh #!/bin/bash #set -x TODAY=`date +%Y%m%d` while read in do echo " Name is $in" done <list.txt exit [root@localhost ~]#
また処理に使用する「list.txt」を作成します。
内容は以下です。
[root@localhost ~]# cat list.txt taro komachi jun [root@localhost ~]#
「taro」「komachi 」「jun」という人物名を記載したテキストファイルです。
では実行してみましょう。
[root@localhost ~]# ./test3.sh Name is taro Name is komachi Name is jun [root@localhost ~]#
実行結果としては、読み込んだファイルの中の名前を「$in」変数へ格納してechoで「Name is」を付与して出力しています。
ファイルの読み込みはwhile文の処理の終了宣言をするための「done」に対して「done <list.txt」とすることでファイルを指定しています。
ちなみに、従来のUnix環境では以下で1行ずつ読み込みが出来ましたがLinuxでループになってしまいます。
[root@localhost ~]# cat test3.sh #!/bin/bash #set -x TODAY=`date +%Y%m%d` while read in | cat list.txt do echo " Name is $in" done exit [root@localhost ~]#
基本的にはfor文と構文は同じですが処理の仕方には注意しましょう。
ifなどと組み合わせて使うと汎用的で便利ですが、かならずループを抜けるための処理を入れるようにしましょう。
覚えておくと良い知識
便利なコマンド① echo $?
シェルスクリプトで非常に有効なコマンドの一つが「echo $?」です。
これは直前のコマンドの「実行結果」をコードで表示するコマンドです。
バッチスクリプトで言えば「ERRORLEVEL」変数に該当するものです。
以下は正常にコマンドが成功した場合です。
[root@localhost ~]# echo $? 0 [root@localhost ~]#
逆にコマンドが失敗した場合は「0」以外の結果コードが返されます。
[root@localhost ~]# data bash: data: コマンドが見つかりませんでした... [root@localhost ~]# [root@localhost ~]# echo $? 127 [root@localhost ~]#
直前のコマンドの実行結果や処理結果をもって、処理を継続したり中断する場合はこのコマンドが一番簡単で使いやすいです。
CLIからのオペレーションよりもシェルスクリプトでこそ活きるコマンドです。
便利なコマンド② sed
次に便利なのが「sed」です。
使い方によっては膨大なパターンがありますが、今回はベーシックな記述を紹介したいと思います。
「sed」は文字列の置換に特化しているため、データの加工に欠かせないコマンドです。
では先ほどの「list.txt」を置換してみます。
[root@localhost ~]# cat list.txt | sed -e 's/taro/ichiro/g' ichiro komachi jun [root@localhost ~]#
これは「taro」にマッチするもじれるを「ichiro」へ置換しています。
なのでコマンドの結果は「ichiro」になって標準出力されています。
また正規表現も使う事が出来ます。
[root@localhost ~]# cat list.txt | sed -e 's/^/Namae is /g' Namae is taro Namae is komachi Namae is jun [root@localhost ~]#
正規表現での「^」は行頭を意味します。
つまり行頭を「Name is」へ置換する事で、名前の前に値を付与しています。
このように汎用的に文字列を置換出る「sed」コマンドもシェルスクリプトでデータ加工させる場合などには非常に有用です。
リダイレクト
リダイレクトはログ出力やcronでは頻繁に用いる手段です。
こちらもコマンドベースで実行が可能です。
[root@localhost ~]# cat list.txt | sed -e 's/^/Namae is /g' > list.log
この「>」がリダイレクトになります。
コマンドやシェルスクリプトの内容を別ファイルへ書き出すための動作です。
今回は「list.log」にコマンドの結果を出力しています。
このコマンドで「list.log」ファイルは自動作成されますが追記にする場合は「>>」にします。
[root@localhost ~]# cat list.txt | sed -e 's/^/Namae is /g' >> list.log [root@localhost ~]# cat list.log Namae is taro Namae is komachi Namae is jun Namae is taro Namae is komachi Namae is jun [root@localhost ~]#
このように、1回目の実行結果と、追記式でリダイレクトさせた結果が反映されるので、同じ処理結果が追記されています。
このようにコマンドやシェルスクリプトの処理結果を残すにはリダイレクトは必須ですし現場でもあり前のように使われています。
基本的な知識ですが、どのレベルで仕事をするにも必要ですのでリダイレクトの操作も複数パターンあるので覚えておくと良いでしょう。
シェルスクリプトの学習ですがこちらの書籍に関して記事を書いていますので本格的に学習したい人は参考にして頂ければと思います。
最後に
シェルスクリプトの基礎的な内容について書いてきました。
Linux自体が取っつきにくいOSではありますが慣れてしまえばWindowsよりも便利に感じる人も多いです。
また、Linuxでのサーバ操作だけではなくシェルスクリプトが書ける方がエンジニアとしては評価が高まります。
簡単で基礎的な構文しか解説していませんが、これらを抑えてれば基本的には問題なく書けるようになると思います。
他にもcase文や外部ファイルの変数読み込みなどの知識もありますが、今回は基礎という事でここまでにしたいと思います。
次回はもう少し踏み込んだ知識をご紹介したいと思います。