サーバ管理者のためのプログラミング入門(シェルプログラミング基礎4~シェルスクリプト変数その2) [サーバ管理者のプログラミング]
前アーティクルにおいて一通り変数の使い方を紹介したが、さらに重要な特殊な(?)変数がある。これらの変数はシェルスクリプトを作成してゆく中で重要な役割を担うので覚えておいてもらいたい。
その1:$?
変数の名前に「?」というものがある。
これは、「直前に実行されたコマンドの、終了ステータス」が獲得できる変数となっている。
「終了ステータス」とはどういうことか。それは、要するにコマンドが正常終了したか否かを判断できるもの…と理解してもらってもまあ差し支えないと思う。
実例を見てみよう。たとえば、pingコマンドで試す。pingが通った場合から見てみよう。
localhostにpingを投げている例。当然応答があるので正常な実行結果ということになる。
pingコマンドの直後に$?の内容を確認すると「0」が入っていることが判る。
ほとんど全てのコマンドは、「0」が入っていたときはコマンドは正常に終了したことを表している。
続いて、機器の存在しないIPアドレスに対してpingコマンドを実行したらどうなるか。
今度は「1」が入っていた。
コマンドとしては異常終了していることを意味している。
続いて、hostsやDNSで名前解決できない場合はというと…
今度は「2」になっている。
pingコマンドは、異常終了した場合「終了ステータス」に異常だった理由を入れている。まあ、あまり深く気にすることはそう多くないと思うが。
というわけで、「$?」が0だったか、0じゃなかったか…によって、コマンドが正常に終了したか、異常終了したかが判断できるのであった。
その2:$!
今度は、変数名「!」について。
これは「直前に実行したバックグラウンドプロセスのPID」を意味する。
これも実例を見てみよう。
sleepコマンドをバックグラウンドで実行して、そのPIDを調べてみると…
このように、バックグラウンドで実行されているであろうsleepコマンドのPIDが表示され、一致している。
本当に一致しているか、psコマンドで確認してみると…
fgrepコマンドも一緒に引っかかっているが、確かにsleepコマンドのPIDそのものである。
killコマンドでsleepコマンドを強制終了させてみる。
間違いなくsleepコマンドが消えてなくなった。
この変数はバックグラウンドでコマンドを実行中に別のことを実行するなどする際に役立つ。
その3:$$
続いて変数名「$」。これは、「現在実行中のコマンドラインインタプリタ…つまりshとかbashとか…のPID」を意味する変数になる。
これも実例から見てみよう。
子プロセスも表示されているが、変数「$$」に入っている数値1390は、bashのPIDと確かに一致していることがわかる。
では、現在のbashから、さらに子プロセスとしてbashを実行するとどうか。
先ほどと同じターミナルで実行しているが、別の数値が表示されている。同時に実行したpsコマンドにも4501というPIDでbashが表示されている。
PIDが変化してしまった?という疑いを晴らすため、再度確認してみるが…
やはり同じPIDで変化していないことが確認できた。
その4:位置パラメータ
今度は、「位置パラメータ」の出番。
「$」記号に続けて数値を記述すると、それは「位置パラメータ」を示す変数となる。
「$1」は一番目のパラメータ、「$2」は二番目のパラメータ…「$3」なら三番目のパラメータ…という具合。
「位置パラメータ」とはそもそも何?という人もいるだろう。簡単に言うと、コマンドに続けて記述しているオプションや引数のことである。たとえば、「ls -la /tmp」というコマンドを例にとると、
・最初の「ls」…コマンド名 (実は、「$0」という変数にこの名前が入っている)
・オプション「-la」…第1パラメータ → これは「$1」に入っている
・引数「/tmp」…第2パラメータ → これは「$2」に入っている
こんな具合だ。簡単なシェルスクリプトで実際に試してみよう。
まず、以下のようなシェルスクリプトを用意してみた。
chmod +xして、とりあえず実行してみよう。すると…
こんな具合に。
では、適当にパラメータとか記述してみるとどうなるだろか。
パラメータを3個並べてみると、それぞれ1~3にそれぞれの文字列が入っていることが判る。これが「位置パラメータ」である。(C/C++的表現では「argv」に相当する)
で、この「位置パラメータ」が何個列挙されているか知りたいこともあるだろう。そのような情報を格納するのが変数「$#」である。
先ほどのシェルスクリプトを以下のように改造してみよう。
これを先ほどと同じように実行すると…
引数を何も書かずに実行すると、変数「$#」には0が。3個つけて実行すると変数「$#」には3が入っている。これによって、「位置パラメータの個数」を知ることが可能となるのである。(C/C++的表現では「argc」に相当している)
また、「位置パラメータ」を分割せずにそのままの形で欲しい!という時もある。そのような時には変数「$*」を用いると良い。
先ほどのシェルスクリプトをさらに改造する。
これを再度同じように実行すると…
…という具合になる。
ひとまず覚えておきたい基本的な変数はこんなところかな。
次はいよいよプログラミングっぽい感じのすることをやってみることとする。
その1:$?
変数の名前に「?」というものがある。
これは、「直前に実行されたコマンドの、終了ステータス」が獲得できる変数となっている。
「終了ステータス」とはどういうことか。それは、要するにコマンドが正常終了したか否かを判断できるもの…と理解してもらってもまあ差し支えないと思う。
実例を見てみよう。たとえば、pingコマンドで試す。pingが通った場合から見てみよう。
[root@kagami ~]# ping -c 1 localhost PING kagami (127.0.0.1) 56(84) bytes of data. 64 bytes from kagami (127.0.0.1): icmp_seq=1 ttl=64 time=0.159 ms --- kagami ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.159/0.159/0.159/0.000 ms [root@kagami ~]# echo $? 0
localhostにpingを投げている例。当然応答があるので正常な実行結果ということになる。
pingコマンドの直後に$?の内容を確認すると「0」が入っていることが判る。
ほとんど全てのコマンドは、「0」が入っていたときはコマンドは正常に終了したことを表している。
続いて、機器の存在しないIPアドレスに対してpingコマンドを実行したらどうなるか。
[root@kagami ~]# ping -c 1 192.168.10.99 PING 192.168.10.99 (192.168.10.99) 56(84) bytes of data. --- 192.168.10.99 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms [root@kagami ~]# echo $? 1
今度は「1」が入っていた。
コマンドとしては異常終了していることを意味している。
続いて、hostsやDNSで名前解決できない場合はというと…
[root@kagami ~]# ping null.void ping: unknown host null.void [root@kagami ~]# echo $? 2
今度は「2」になっている。
pingコマンドは、異常終了した場合「終了ステータス」に異常だった理由を入れている。まあ、あまり深く気にすることはそう多くないと思うが。
というわけで、「$?」が0だったか、0じゃなかったか…によって、コマンドが正常に終了したか、異常終了したかが判断できるのであった。
その2:$!
今度は、変数名「!」について。
これは「直前に実行したバックグラウンドプロセスのPID」を意味する。
これも実例を見てみよう。
sleepコマンドをバックグラウンドで実行して、そのPIDを調べてみると…
[root@kagami ~]# sleep 60000 & [1] 4485 [root@kagami ~]# echo $! 4485
このように、バックグラウンドで実行されているであろうsleepコマンドのPIDが表示され、一致している。
本当に一致しているか、psコマンドで確認してみると…
[root@kagami ~]# ps -ef | fgrep "4485" root 4485 1390 0 17:31 pts/0 00:00:00 sleep 60000 root 4487 1390 0 17:31 pts/0 00:00:00 fgrep 4485
fgrepコマンドも一緒に引っかかっているが、確かにsleepコマンドのPIDそのものである。
killコマンドでsleepコマンドを強制終了させてみる。
[root@kagami ~]# kill 4485 [root@kagami ~]# [1]+ 終了しました sleep 60000 [root@kagami ~]# ps -ef | fgrep "4485" root 4489 1390 0 17:31 pts/0 00:00:00 fgrep 4485
間違いなくsleepコマンドが消えてなくなった。
この変数はバックグラウンドでコマンドを実行中に別のことを実行するなどする際に役立つ。
その3:$$
続いて変数名「$」。これは、「現在実行中のコマンドラインインタプリタ…つまりshとかbashとか…のPID」を意味する変数になる。
これも実例から見てみよう。
[root@kagami ~]# echo $$ 1390 [root@kagami ~]# ps -ef | fgrep 1390 root 1390 1386 0 Jan18 pts/0 00:00:00 -bash root 4496 1390 0 17:38 pts/0 00:00:00 ps -ef root 4497 1390 0 17:38 pts/0 00:00:00 fgrep 1390
子プロセスも表示されているが、変数「$$」に入っている数値1390は、bashのPIDと確かに一致していることがわかる。
では、現在のbashから、さらに子プロセスとしてbashを実行するとどうか。
[root@kagami ~]# bash -c 'echo $$;ps -ef | fgrep $$' 4501 root 4501 1390 0 17:40 pts/0 00:00:00 bash -c echo $$;ps -ef | fgrep $$ root 4502 4501 0 17:40 pts/0 00:00:00 ps -ef
先ほどと同じターミナルで実行しているが、別の数値が表示されている。同時に実行したpsコマンドにも4501というPIDでbashが表示されている。
PIDが変化してしまった?という疑いを晴らすため、再度確認してみるが…
[root@kagami ~]# echo $$ 1390 [root@kagami ~]# ps -ef | fgrep 1390 root 1390 1386 0 Jan18 pts/0 00:00:00 -bash root 4506 1390 0 17:42 pts/0 00:00:00 ps -ef root 4507 1390 0 17:42 pts/0 00:00:00 fgrep 1390
やはり同じPIDで変化していないことが確認できた。
その4:位置パラメータ
今度は、「位置パラメータ」の出番。
「$」記号に続けて数値を記述すると、それは「位置パラメータ」を示す変数となる。
「$1」は一番目のパラメータ、「$2」は二番目のパラメータ…「$3」なら三番目のパラメータ…という具合。
「位置パラメータ」とはそもそも何?という人もいるだろう。簡単に言うと、コマンドに続けて記述しているオプションや引数のことである。たとえば、「ls -la /tmp」というコマンドを例にとると、
・最初の「ls」…コマンド名 (実は、「$0」という変数にこの名前が入っている)
・オプション「-la」…第1パラメータ → これは「$1」に入っている
・引数「/tmp」…第2パラメータ → これは「$2」に入っている
こんな具合だ。簡単なシェルスクリプトで実際に試してみよう。
まず、以下のようなシェルスクリプトを用意してみた。
#!/bin/sh echo 0","$0 echo 1","$1 echo 2","$2 echo 3","$3
chmod +xして、とりあえず実行してみよう。すると…
[root@kagami ~]# /tmp/param_test.sh 0,/tmp/param_test.sh 1, 2, 3,
こんな具合に。
では、適当にパラメータとか記述してみるとどうなるだろか。
[root@kagami ~]# /tmp/param_test.sh konata miyuki tsukasa 0,/tmp/param_test.sh 1,konata 2,miyuki 3,tsukasa
パラメータを3個並べてみると、それぞれ1~3にそれぞれの文字列が入っていることが判る。これが「位置パラメータ」である。(C/C++的表現では「argv」に相当する)
で、この「位置パラメータ」が何個列挙されているか知りたいこともあるだろう。そのような情報を格納するのが変数「$#」である。
先ほどのシェルスクリプトを以下のように改造してみよう。
#!/bin/sh echo "#,"$# echo 0","$0 echo 1","$1 echo 2","$2 echo 3","$3
これを先ほどと同じように実行すると…
[root@kagami ~]# /tmp/param_test.sh #,0 0,/tmp/param_test.sh 1, 2, 3, [root@kagami ~]# /tmp/param_test.sh konata miyuki tsukasa #,3 0,/tmp/param_test.sh 1,konata 2,miyuki 3,tsukasa
引数を何も書かずに実行すると、変数「$#」には0が。3個つけて実行すると変数「$#」には3が入っている。これによって、「位置パラメータの個数」を知ることが可能となるのである。(C/C++的表現では「argc」に相当している)
また、「位置パラメータ」を分割せずにそのままの形で欲しい!という時もある。そのような時には変数「$*」を用いると良い。
先ほどのシェルスクリプトをさらに改造する。
#!/bin/sh echo "#,"$# echo 0","$0 echo 1","$1 echo 2","$2 echo 3","$3 echo "*,"$*
これを再度同じように実行すると…
[root@kagami ~]# /tmp/param_test.sh #,0 0,/tmp/param_test.sh 1, 2, 3, *, [root@kagami ~]# /tmp/param_test.sh konata miyuki tsukasa #,3 0,/tmp/param_test.sh 1,konata 2,miyuki 3,tsukasa *,konata miyuki tsukasa
…という具合になる。
ひとまず覚えておきたい基本的な変数はこんなところかな。
次はいよいよプログラミングっぽい感じのすることをやってみることとする。
コメント 0