UNIXメモ / 作成: 2001-11-15
はじめ私は、単なる対話的UNIX利用の延長として Cシェルでスクリプトを書いていたのだが、 修士論文を書く直前のクリスマス頃に、 Bシェルスクリプトをマスターして切り替えた。 ある短い数値計算プログラムを、冬休みじゅうの時間を使って、 可能な限り多くのパラメータ値で走らせる必要があったのだ。 それで本格的にシェルスクリプトを勉強する必要があったから、 当時の研究室の先輩に尋ねて、 京大計算機センターの連載記事
誰にでも書ける #! /bin/sh講座 (安岡孝一)を見て勉強したのだった。 (なお、この連載記事は、 のちに単行本「誰にでも使えるUnix講座」としてまとめられたようだ。)
※ だいぶ後になってから知ったのだが、 Cシェルはコマンドプロンプト用には有効でも スクリプトには全く不向きであり、 シェルスクリプトは基本的にBシェルで書くものだと言われている。 Cシェルがスクリプトに向かない理由については、 「なぜ csh でプログラムを書くのが良くないのか」 (森 大毅 訳)に くわしく書かれている。
当時から私はAWK使いだったから、 Bシェルスクリプト + AWKプログラム で いろんなものを書いた。 FORTRANプログラムを解析するツールまで書きかけたことがある。 その後、21世紀になってからPerlを習得し、現在に至っている。
たとえば、UNIXのcalコマンドは
% cal 12 2001で2001年12月のカレンダーを出力するが、
% cal 2001 12とすると、2001年12月とは認識してくれない。 この点を改良したコマンドを、シェルスクリプトで作ってみよう。
まずは、次のような内容のファイルを作る。 ファイル名は、仮にmycalとでもしておこう。
#! /bin/sh CAL=/usr/bin/cal # 本物のcalプログラム if [ $# -eq 2 ] then A=$1; B=$2; if [ $A -le 12 ] then MONTH=$A; YEAR=$B; else MONTH=$B; YEAR=$A; fi $CAL $MONTH $YEAR else $CAL $@ fi
重要な点は、ファイルのいちばん最初を #! にすることである。 前に空白や空行があってはいけない。 なお、#! の直後の空白は あってもなくても動作するようである。
さて、このファイルを mycal という名前でセーブしたとしよう。 次にすることは、 このファイルの属性を実行可にすることだ:
% chmod u+x mycalそして、いよいよ実行:
% ls -l mycal
% ./mycal 2001 11これで2001年11月のカレンダーが表示されれば成功である。
うまくいかない場合、エラーメッセージを見て、 ファイルにおかしいところがないかどうかをさがす。 3行目の /usr/bin/cal の部分は、
% which calというコマンドを実行して、 その結果に応じて変更する必要があるかもしれない。 また、イコールの前後に空白があると うまく作動しない。
何か適当なCプログラムなりFORTRANプログラムなりがあるとする:
implicit none real x write(0,*) 'input: x = ' read(*,*) x ! 標準入力から読み込む write(*,*) x * log(x) ! 標準出力に書き出す stop end
上記のプログラムは、 データを標準入力から読み込み、 計算結果を標準出力に書き出すようになっている。 この例ではあまりに単純だが、まあ、たとえば 何か複雑なプログラムをCで書いたとしよう。 そのプログラムは、 やはり何か(たとえばReynolds数などのパラメータ)を標準入力から読み込み、 結果を標準出力に出力するものだとする。 このプログラム(仮にprog01とする)を、 たとえば5つのパラメータで走らせたいとすると、 次のようなシェルスクリプトが役立つかもしれない:
#!/bin/sh for R in 1 2 3 4 5 do PARFILE="reynolds${R}.par" DATFILE="reynolds${R}.dat" echo $R | awk '{ print 0.1 * $1; }' > $PARFILE # パラメータの値 ./prog01 < $PARFILE > $DATFILE done
なお、最初の行の #!/bin/sh を
#!/bin/sh -vxとすると、シェルスクリプトの実行の過程をくわしく追うことができる。
じつは、UNIX系のシステムでは
#! /bin/shだけでなく さまざまな種類のスクリプトを実行できるようになっている。 たとえば
#! /usr/bin/perl -wだと Perlスクリプト、
#! /usr/bin/awk -fだと AWKスクリプトが実行される。
これはどういうことかというと、 たとえば myscript01 というファイルの最初が
#! /bin/shとなっている場合、UNIX系OSは この行を読みとって
/bin/sh myscript01を実行するのである。 別の言い方をするなら、 たとえ最初の#!とか実行属性とかがなくても、 スクリプト本体さえ書いてあれば、コマンドラインから
% /bin/sh myscript01と入力することにより シェルスクリプトの実行は可能である。 最初の#!は、このようなコマンドラインと等価な内容を 自動的に実行するものだと言える。
UNIX系OSでの日本語入力が今よりもさらに不便だったころ、 私は、次のようなスクリプトを作って愛用していた:
#!/usr/bin/tail -1 大信田 丈志
このスクリプトのファイル名はmynameである。 したがって、コマンドラインから
% mynameと入力すると、システムはこれを
/usr/bin/tail -1 mynameと置き換えて実行するので、 私の名前が出力される、というわけだ。 (ちなみに、今は、 mynameを もう少し高機能にしたものを作って愛用している。)