Programmer's Note

コード読み書きの備忘録。

shプログラミング覚え書き

shって使いこなせばかなり便利だな。プログラミング言語としても面白い。(※注:Bourne Shell系のshell)

「The UNIX Programming Environment」の第5章の"SHELL PROGRAMMING"を読んでいる途中だが、 いろいろおさらいしときたいTIPSがある。

とありえず手元のMax OS XGNU bashで、適当に動かしながら確認してみる。

setコマンド

単に

$ set

と打つと、今設定されている環境変数の一覧がでてくる。しかし、

$ set abcd

とうつと、なんと'abcd'を変数$1に格納してくれる。以降スペースを空けて渡された引数ごとに、$2、$3、$4・・と保存してくれる。

$ set aaa bbb ccc
$ echo $1
aaa
$ echo $2
bbb
$ echo $3
ccc

「The UNIX Programming Environment」の中では、

$ set `date`

とdateコマンドの出力を$1, $2, ...変数に格納して、個別に取り出していた。 なるほど、便利だ。 awkを使っても同じことができるが、格段に短く記述できる。 例えば、時間”Wed Feb 18 21:30:45 JST 2015”の時刻だけ取り出したい場合

$ set `date`
$ echo $4
21:31:53

とし、$4はそのままシェルスクリプトの中で、使い続けられる。 おなじことをawkでやろうと思うと、

$ time=`date | awk '{print $4}'`
$ echo $time
21:31:53

とする。まあ、十分短いけれど。 その他のフィールドも、$1, $2 ...と使えるので、コマンドの一行結果の即時利用に関してはawkに比べて利便性が高い。

for文

shのfor文は強烈だ。構文は、

for var in command
do
  ...
done

だが、commmandの部分は、空白で区切られた文字列を返せば、何でもOKで、どんな長いコマンドでもOK。「The UNIX Programming Environment」の使用例で素晴らしいと思ったのは、sedとの組み合わせの例で、whichコマンドを実現しているスクリプト。 以下、command部だけ抜き出したような感じだが、

for i in `echo $PATH | sed 's/^:/.:/
                            s/::/:.:/
                            s/:$/:./
                            s/:/ /g'`
do
 ・・・
done

上記は、PATHに入ってるディレクトリの羅列をスペースで区切るように変換している。PATHのディレクトリはコロン(:)で区切るがこれをスペースに変換している。その前に、PATHの中で空文字+コロンの場合は、カレントディレクトリを示すので、これをピリオドに置換している。(これが左端、中、右端の3パターン)と。 sedが置換作業を複数個同時に記述できる(改行が必要だが)のも素晴らしいが、それをそのままfor文に渡しているのに、まったく可読性がおちないところが素晴らしい。

そして、なんともまあcommandを省いた省略形も書ける。

for i
do
 echo $i
done

は、i には何も渡されてないように見えるが、これはシェルスクリプトにしたときに、 スクリプトに渡された引数が入る。たとえば、上記をtest.shに入れたとして、

$ test.sh 1 2 3
1
2
3

となる。 以前書いた記事 bundleプログラム改 - Programmer's Dialy で使っている。

case文

case文は簡易的な正規表現使えるところが強力だねえ。 以下のような適当なtest.shを書いたとする。

#!/bin/sh
case $1 in
data??.txt) echo "$1 is data";;
esac

実行:

$ test.sh data01.txt
data01.txt is data

表現的には

case $1 in
data[0-9][0-9].txt) echo "$1 is data";;
esac

あるいは、

case $1 in
data*1.txt|data*2.txt) echo "$1 is data";;
esac

も可。 最新のbashだともうちょっと正規表現の幅が広がってるんだろか。

以上。