• このエントリーをはてなブックマークに追加

脱初心者!シェルスクリプトで覚えたい3つのテクニック

  • このエントリーをはてなブックマークに追加

bash
zaco muraです。

サーバエンジニアに求められる技術の一つにシェルスクリプトがあります。どちらかと言うと開発者っぽい作業ですが、簡単な監視ツールなどを作る機会は意外と多いものです。私も数え切れないほどシェルスクリプトを書いてきましたが、自分が覚えて役立ったテクニックをご紹介しようと思います。

この記事の対象

タイトルにもありますが、脱初心者を目指すような人向けです。少しシェルスクリプトは書けるけど、複雑なことができないような人が対象です。

スポンサーリンク
Sponsords Link

そもそもシェルスクリプトとは

簡単に言うと、linuxのコマンドを自動的かつ順番に実行するプログラムです。windowsで言うと.bat拡張子のバッチファイルですね。これによりサーバエンジニアが行う様々な作業を定型化することができ、定期実行させたり、作業時間を短縮したりできます。

初心者を脱するために必要なテクニック

あくまでも私の例ですが、初心者の頃は単純にコマンドを並べただけのシェルスクリプトを書いていました。もちろんそれでもちゃんと動くんですが、少し複雑なことをしようと思うとそれだけでは不十分な場合が多いです。今回は複雑なことをするために必要なテクニックのうち、以下3つをご紹介します。


1.コマンドの中で別コマンドを実行する
2.コマンドラインから引数を渡す
3.ファイルの内容を読み込む

このテクニックを使えば、(見栄えや長さを気にしなければ)たいていのことはできるようになると思います。それでは、早速説明していきます。

0.簡単なシェルスクリプトを書いてみる

ということで、例題として簡単なスクリプトを書いてみます。内容としては、あるIPアドレスにpingを1発打つだけというシンプルな内容です。これに少しずつ改良を加えていきます。
ソースコードはこちら

#!/bin/bash
ping -c 1 8.8.8.8

はい、至ってシンプルですね。たった2行です。
これを実行するとこんな感じになります。

[zacomura @server ~]$ sh ping.sh 
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=55 time=2.03 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 2.030/2.030/2.030/0.000 ms

はい、無事動きました。pingの実行結果がちゃんと表示されています。それではこのシェルスクリプトを改良し、より複雑なことができるようにしていきます。

1.コマンドの中で別コマンドを実行する

先ほどの内容でも実行結果は表示されていますが、知らない人が見ると表示の意味がわかりづらいですよね。実際に必要なところは実行結果のサマリである下から2行目、つまり”1 packets transmitted, 1 received, 0% packet loss, time 2ms”だけで十分です。また、この表示が何なのかの説明もしてあげたほうが親切です。
ソースコードを以下のように変えてみましょう。

#!/bin/bash
echo "pingの実行結果は `ping -c 1 8.8.8.8 | tail -2 | head -1` でした"

少し変わりました。実行してみましょう。

[zacomura @server ~]$ sh ping.sh 
pingの実行結果は 1 packets transmitted, 1 received, 0% packet loss, time 2ms でした

いかがでしょうか。これなら誰が見てもpingの実行結果であることがわかりますね。
この例では、echoコマンドの中でpingコマンドを実行しているのがわかるかと思います。
このように ` ` で囲むことで コマンド内で別コマンドを実行することが可能になるのです。

2.コマンドラインから引数を渡す

先ほどの内容ではpingを1発だけ打っていますが、状況によっては数発打った方が良い場合もあるかと思います。なので、ここは可変のパラメータにして実行時に決められるようにしましょう。
ソースコードは以下のようになります。

#!/bin/bash
echo "pingの実行結果は `ping -c ${1} 8.8.8.8 | tail -2 | head -1` でした"

どこが変わったかわかりますでしょうか。ping -c の後が、${1}となっています。それでは実際に実行してみます。今度はpingの回数を合わせて入力してあげます。

[zacomura @server ~]$ sh ping.sh 1
pingの実行結果は 1 packets transmitted, 1 received, 0% packet loss, time 1ms でした
[zacomura @server ~]$ sh ping.sh 2
pingの実行結果は 2 packets transmitted, 2 received, 0% packet loss, time 1004ms でした
[zacomura @server ~]$ sh ping.sh 3
pingの実行結果は 3 packets transmitted, 3 received, 0% packet loss, time 2006ms でした

ping.shの隣の数値を1,2,3と変えていくと、実行結果も1,2,3と変わっていることがわかると思います。
このように、${1} というのは、1つ目の引数という意味になります。引数というのはプログラムに渡すパラメータのことです。このように可変のパラメータを引数から渡すことで、シェルスクリプトの汎用性は大幅に高まります。

3.ファイルの内容を読み込む

ここまでの内容では、pingの実行先は8.8.8.8だけになっています。しかし、複数のサーバを同時に監視したいということはよくあります。今回はこのIPアドレスを可変パラメータにし、ファイルから読み込むようにしましょう。
ソースコードを以下のように変えてみましょう。

#!/bin/bash
while read IPADDR ; do
  echo "${IPADDR} のpingの実行結果は `ping -c ${1} ${IPADDR} | tail -2 | head -1` でした"
done < ping_list.txt

今回は大きく変わりました。変更内容としては、pingの実行先を”ping_list.txt”というファイルから取得するようになっています。
ping_list.txtの内容は以下のようにします。

[zacomura @server ~]$ cat ping_list.txt
4.4.4.4
5.5.5.5
6.6.6.6
7.7.7.7
8.8.8.8

それでは実際に実行してみましょう。

[zacomura @server ~]$ sh ping.sh 1
4.4.4.4 のpingの実行結果は 1 packets transmitted, 0 received, 100% packet loss, time 10000ms でした
5.5.5.5 のpingの実行結果は 1 packets transmitted, 0 received, 100% packet loss, time 10000ms でした
6.6.6.6 のpingの実行結果は 1 packets transmitted, 0 received, 100% packet loss, time 10000ms でした
7.7.7.7 のpingの実行結果は 1 packets transmitted, 0 received, 100% packet loss, time 10000ms でした
8.8.8.8 のpingの実行結果は 1 packets transmitted, 1 received, 0% packet loss, time 2ms でした

ping_list.txtに書いたIPアドレスに対して、繰り返しpingを実行していることがわかると思います。
解説すると、”while read IPADDR ; do 〜〜〜 done < ping_list.txt" というのが、ping_list.txtを1行ずつ読み込みIPADDRという変数に格納し、行数分繰り返すという意味になります。この変数をpingの宛先にするには${IPADDR}とすれば使えます。

参考:デバッグする

ここまででシェルスクリプトのテクニックを紹介しましたが、どんなスクリプトでもうまく動かない場合があります。そんな時のデバッグ方法もご紹介しておきます。

[zacomura @server ~]$ sh -x ping.sh 1
+ read IPADDR
++ ping -c 1 4.4.4.4
++ head -1
++ tail -2
+ echo '4.4.4.4 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした'
4.4.4.4 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした
+ read IPADDR
++ ping -c 1 5.5.5.5
++ tail -2
++ head -1
+ echo '5.5.5.5 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした'
5.5.5.5 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした
+ read IPADDR
++ ping -c 1 6.6.6.6
++ tail -2
++ head -1
+ echo '6.6.6.6 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした'
6.6.6.6 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした
+ read IPADDR
++ ping -c 1 7.7.7.7
++ head -1
++ tail -2
+ echo '7.7.7.7 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした'
7.7.7.7 のpingの実行結果は "1 packets transmitted, 0 received, 100% packet loss, time 10000ms" でした
+ read IPADDR
++ tail -2
++ ping -c 1 8.8.8.8
++ head -1
+ echo '8.8.8.8 のpingの実行結果は "1 packets transmitted, 1 received, 0% packet loss, time 1ms" でした'
8.8.8.8 のpingの実行結果は "1 packets transmitted, 1 received, 0% packet loss, time 1ms" でした
+ read IPADDR

このように”-x”オプションをつけることで、どのような内容を実行しているかを細かく表示してくれます。失敗している箇所などを確認するためには重宝します。

まとめ

ということで、シェルスクリプトのテクニックをご紹介しました。ここまでテクニック的なことを説明してきましたが、なんだかんだ言ってシェルスクリプト上達の一番の秘訣はとにかくたくさん書いてみることだと思います。考えるより、まず手を動かしてたくさん書いてみましょう!

スポンサーリンク
Sponsords Link
  • このエントリーをはてなブックマークに追加

ZacoDesign

スポンサーリンク
Sponsords Link