[Shell] 研究に使うUNIXとその機能

私(金野)が研究活動の中で使ってきたUNIXのコマンドや機能のうち、特にプログラムを製作する過程で有用なものを中心に説明します。「流体研ローカルガイド」という名前で、主に卒論生向けに書いてきた文書から、UNIXの一般論について書かれた(つまり、ローカルではない)部分を抜き出して引っ越してきました。研究室内の人にしか見られないよりは、多くの人に見てもらえる方が、書く方も励みになり筆が進みます。

ただし内容は流体研のワークステーションの事情に即しており、流体研の学生向きに書いています。そのへんをご勘案下さい。

未完成だった「バージョン管理」の節を加筆(2000/4/19, 25, 28)
シェルの節を独立したページに引っ越し(2000/8/2)
バージョン管理の節を独立したページに引っ越し(2000/8/2)

あなたはだいたい ???人目のお客様です。(2000年1月25日以降)


* はじめに---この文書の意図するところとしないところ

この文書の読者としては、コンピュータやUNIXには詳しくないが、研究活動の一環としてUNIX環境下でプログラムを書く必要のある人、特に理系の大学生や大学院生を想定している。文書の目的は、できるだけ効率のよいプログラミングを行えるよう、著者なりのアドバイスをすることにある。ここで「効率のよい」というのは、プログラム自体の動作が速いという意味ではなく、すばやくプログラムを作成することができる、という意味である。

著者の所属する研究室"流体研"では、実験データの解析と数値計算の目的で、著者や多くの学生がプログラミングを行っている。そのため以下の文書は主にそのような目的に適したUNIXの機能と、プログラミングの方法を説明している。決して万人に通用するような内容ではないし、またそれを意図してもいない。

UNIXの入門書や手引書としての利用は想定していない。UNIXの入門書は本屋に行くと非常に多くの種類が販売されているので、その中から自分にあった書籍を選ぼう。

同様に、CやFORTRANなどのプログラミング言語の手引きとしての利用も想定していない。

* 目的に合ったプログラミングを

プログラムの作成過程の効率を上げ、なるべく楽をするためには、全体として次のような方針をとるべきである。

しかしここに書いたことはどれも必須ではなく、目的によってはむしろ上に書いた通りにしない方がよい場合もあることを知るべきである。たとえばC言語に精通しており、高いプログラミング能力を持っているのなら、どのような目的に対してもC言語だけを用いて対処できるだろう。また目的によっては、標準入出力を用いないほうが便利な場合や、凝ったインターフェイスを必要とする場合ももちろんあるだろう。この文書もUNIXも、自分の都合に合わせて上手に活用してほしい。


* シェル

シェルの機能について解説した節は、長くなったので、独立したページに引っ越した。そちらを参照してほしい。シェルの機能と概念はUNIXを利用していく上でとても役に立つと思うので、がんばって習得してほしい。

[go!] シェル


* プログラムの作成・実行とシェルの機能

UNIXの概念とシェルの機能を理解していれば、プログラムを作る上で、次のような方針を採ることができると分かる。

それぞれ簡単に説明する。

* 標準入出力の利用

出力ファイルを複数に分けておく必要があるなどの複雑な処理をするプログラムは別として、たいていの場合には通常の出力先に標準出力を、エラーメッセージの出力には標準エラー出力を用いることを勧める。理由は以下の通りである。

ここまで来ると、なぜ標準出力の他に標準エラー出力があるのかを理解できると思う。プログラムの出力はファイルに保存しておきたいが、一方何らかのエラーが発生した場合には、それを画面に表示して教えてほしい、という願望があるからである。

FORTRANの場合には、通常の出力はユニット6番に出力し、エラーメッセージはユニット0番に出力する。

Cの場合には、おそらく高水準入出力を使うだろうから、高水準入出力専用のファイルハンドルstdoutとstderrを使い分ける。

* 単機能プログラム

プログラムに多くの機能を盛り込もうとすると、当然その分だけプログラミングがめんどうになり、時間がかかる。たとえば複数のファイルを順番に処理するようなプログラムを書くのは、技術的には可能だし参考書にその方法が載っているが、それよりは一つのファイルを処理するプログラムを書き、あとはシェルのプログラミング機能を利用する方が、プログラミングが簡単である。

実験データがたくさんあり、それを一つ一つ処理しなければならないときなどに、シェルの繰り返し処理などのプログラミング機能が実に役に立つ。たとえば自作のプログラムdata_processで実験データの処理をする場合を考えよう。実験データのファイル名がexp1101.dat、exp1102.dat、…という名前だったとして、それを一つ一つ処理して、処理した結果をprocessedというディレクトリに保存する、という処理を行うと、次のようになる。(csh, tcshの場合)

% foreach file (exp11??.dat)
?   ./data_process < $file > processed/$file
? end

"%"や"?"はシェルの出すプロンプトなので、本質はそれよりもあとの部分である。またプログラムdata_process は標準入力を読んで処理を行い、結果を標準出力に書くプログラム(フィルタプログラム)になっていることにしている。

シェルのこのような機能を知っていれば、いちいちキーボードを叩いて処理するファイル名を指定する必要はなく、すべて一括して処理してくれるので非常に便利である。この節のはじめのところで「著者なら30秒で終わる仕事を、1 時間以上かかってエッチラオッチラやっているのを見るのは可哀想である。」と書いたが、これはこのシェルの機能を利用しているかいないかで差が出るからだ。

UNIXのシェルは非常に賢い。上手に使って楽をしよう。

* 重い計算を実行するとき

大規模な数値計算など重い計算を実行すると、皆の共有資源であるワークステーションを長時間に渡って使うことになる。その場合には、必要以上に計算機を占有しないための「作法」がある。ここではプログラミングの話からいったん離れて、この作法について説明しておく。

無駄な計算をしない(1): デバッグは済ませておく

プログラムのデバッグのために、長時間の計算を行うのは避ける。どうしても長時間の計算を行わないとバグが発見できないのであれば話は別だが、たいていはその必要はないはずである。無駄な計算のために計算機資源を使わないよう心掛けてほしい。

無駄な計算をしない(2): 最適化

重い計算をするためのプログラムは、最適化をかけてコンパイルしておくべきである。プログラムによっては計算時間が1桁以上異なる。

バックグラウンドでの実行

これはつまりワークステーションのコンソール(キーボードとディスプレイ)を占有するな、ということである。計算中はずっとログインしっぱなしである必要な無いのだ。夜に計算を走らせた状態で、ログアウトせずに帰る学生を見るとあきれる。場合によっては有無を言わさずログアウトするので、流体研の学生は気をつけよう。「計算中なので触らないでください」などのメモや貼紙をつけるくらいなら、この節の内容をよく読んで適切な処置をしてほしい。

まずは形から。calc_somethingというプログラムを実行するとき、次のようにして実行する。

% nohup nice ./calc_something >& file &

">&" はシェルのリダイレクトの機能、最後の "&" はバックグラウンドで実行する意味で、どちらも前の節で説明した。新しく出てきたのはnohup(1)nice(1)で、それぞれ順番に説明する。

まず"nohup"はNo Hang Upの意味で、ログアウトしてもプロセスが終了しないようにするコマンドである。これをつけて実行しなかった場合、ログアウトするときにすべてのプロセスが殺される。(厳密に言うと、プロセスを実行したシェルが終了するときに、そのシェルの子プロセスすべてにHUPシグナルが送られる。HUPシグナルが来ても死なないようにするからnohup。)

"nice"はプロセスの「nice値」を上げるコマンドである。nice値というのはプロセスを実行する優先順位を決める数字で、大きいほど優先順位が低い。だからniceコマンドはプロセスを実行する優先順位を下げることになる。

したがって上のコマンドがやっていることは、次の4つである。

通常の数値計算プログラムであれば、上に述べた手順を踏めば、ログアウトした後でも計算を続けられる。計算を走らせたままでワークステーションを離れる(アルバイトに行く、帰宅するなどの)場合には、必ず上の手順を踏んでほしい。

優先順位を下げる意味

nohupの機能は分かりやすいので理解してもらえるだろうが、niceで優先順位を下げると、計算が遅くなるのではないかと心配するかもしれない。実はその通りで、計算時間が通常よりも遅くなる可能性がある。しかしそれでもniceをつけてほしいので、このへんの事情を説明する。

niceをつけて優先順位を下げても、もしその間に他の人がその計算機を使わなければ、計算時間には影響がほとんど出ないはずである。どんなに優先順位を下げても、他にプロセスが走らなければそのプロセスが実行される、という単純な理由からである。しかし他の人がそのワークステーションにログインして、何らかの作業を行うときは、そちらのプロセスが優先されるから、計算時間はその分遅くなる。

もし重い計算を、niceで優先度を下げずに実行すると、今度はワークステーションにログインして作業したい人に迷惑がかかる。シェルやエディタの反応が鈍くなるからである。経験すると分かるがこれはストレスがたまるものだ。また当然ながら、作業が遅れる分だけワークステーションにログインしている時間が長くなるので、バックグラウンドで走っているプロセスにも影響が出る。

むやみにniceをつけてほしいと願っているわけではない。重くて長くかかる計算をするときだけ、必要に応じてつけてほしい。次のように考えてほしい。

ほんの1、2分の計算時間を惜しむあまりに、計算機資源を占有して他人に迷惑をかけ、人間関係を悪くするのは、私は得策ではないと思う。ワークステーションの利用方法と同様、賢く行動してほしい。


* スクリプト言語のススメ---Awk, Perl

この節は、著者(金野)の個人的意見です。著者はFORTRANやCで苦労するよりも AwkやPerlを学んだ方が得だと信じていますが、FORTRANやCを使っても管理上の不都合は無いので、個人の好みと慣れで判断して下さい。

ごく簡単なデータ処理、ファイル形式の変換、ソートなどには、FORTRANやCでプログラムを書くよりも、Awk(awk(1))、 Perl(perl(1))などのスクリプト言語を利用することを勧める。場合によっては、これらとsort(1)uniq(1)などを組み合わせて使う。

著者は数値計算以外のプログラムのほとんどすべてをPerlで書いている。しかし流体研内では、Awk, Perlはあまり普及していない。 AwkまたはPerlでやればわずか数行のプログラムでできることを、FORTRANの長々としたプログラムでやっているのをたびたび見かけるのが、実に歯痒い。

Awk, Perlの利点は、たとえば以下のような点である。ちなみにPerlのほうがはるかに強力なのでお勧めだが、新しいプログラミング言語の習得にあまり時間をかけたくないのであれば、とっつきやすく使いやすいAwkを勧める。

Awkの参考書の決定版:
A.V.エイホ/B.W.カーニハン/P.J.ワインバーガー 著, 足立 高徳 訳, プログラミング言語AWK, トッパン, 1989.

Perlの参考書はたくさんの種類が販売されているので、決定版をあげるのは難しい。これはウェブのCGIプログラムを作成する言語として、Perlがよく用いられていることが一因だと思われる。Perlの参考書は書店で数冊当たり、自分にとって分かりやすそうなものを選んでほしい。

スクリプト言語は一般に数値計算には向かない。数値計算用のプログラミングには、FORTRAN 77、C++、Matlabなどが使われる。歴史的な事情で、FORTRAN 77の利用がもっとも多い。


* makeの勧め

プログラムの分割コンパイルを行う場合、make(1)は非常に便利で、よく知られたツールである。流体研であまり使われていないのがとても意外だし、残念でならない。ここではmakeのごくごく簡単な機能に触れるので、役立ててほしい。

makeの詳しい機能については、以下のリンクが参考になるだろう。また、GNU makeのinfoがあるのでそちらも参考になろう。

この他に私は次の記事のコピーを手元に置き、Makefileを書くときに参考にしている。

foo.f, bar.f, baz.fの3つのソースファイルからなるプログラムfoobarがあるとする。FORTRANコンパイラでこのプログラムを作成するには、もっとも簡単には次のコマンドを実行する。

% f77 foo.f bar.f baz.f -o foobar

この方法では3つのソースコード全てをコンパイルし、プログラムfoobarを作っている。この方法の欠点は、まずコマンドラインが長くなること。そして、 foo.fを修正して再コンパイルする場合に、修正されていないソースファイル bar.f, baz.fも再コンパイルされてしまうことである。これは効率が悪いので、次のようにオブジェクトファイルを作成する方法を取るとしよう。

% f77 -c foo.f
% f77 -c bar.f
% f77 -c baz.f
% f77 foo.o bar.o baz.o -o foobar

この方法の場合は、foo.fを修正した場合にはbar.fとbaz.fのコンパイルは必要ない。修正が加えられたファイルだけを再コンパイルすればよい。

makeは上記の作業を自動化するためのプログラムである。自動化することにより、「ソースファイルを修正したのに再コンパイルし忘れた」などのつまらないミスを無くし、作業効率を高めることができる(このようなミスは、実は研究の過程でしょっちゅうやってしまう)。makeはMakefileというファイルを読んで動作を決めるので、プログラムの依存関係をこのファイルに書いておく。具体的には次のようなファイルを作る。

@SHARP@ Makefile for foobar

@SHARP@ "#"以下はコメントとして扱われる。


@SHARP@ "f77"の前の字下げはTABで行うこと。
foobar: foo.o bar.o baz.o
        f77 foo.o bar.o baz.o -o foobar

foo.o: foo.f
bar.o: bar.f
baz.o: baz.f

この例は非常に簡単な例だが、それでもmakeの機能のいくつかを利用して楽をしている。まず、makeはxxx.fからxxx.oを作る方法を知っているので、依存関係だけを記述すればコマンドを書く必要は無い。(実は依存関係を書かなくともよい。 makeが適切に判断してくれる。) オブジェクトファイルから実行プログラムを作る部分だけはきちんと書いておく。

ここまで出来たら後は簡単。makeコマンドを実行するだけである。

% make

これで、必要に応じてプログラムが実行され、foobarが作られるはずである。 makeは非常に便利なツールなので、ぜひ利用して作業の効率を上げてほしい。


* バージョン管理

バージョン管理とCVSについて解説した節は、長くなったので、独立したページに引っ越した。そちらを参照してほしい。

[go!] バージョン管理

ソースコードの「バージョン管理」はとても便利で有意義な手段である。プログラムをどんどん書き換えていろいろ試し、うまく行かなかったらまた元に戻すとか、先輩の書いたプログラムを元にして機能を拡張したプログラムを作るなどの場合にその力を発揮するので、特に卒論生など、まだプログラミングを学びはじめたばかりの研究者にはお勧めしたい。


<- トップページ
工学院大学機械工学科流体研

リンクはご自由に。でもメールをくれると嬉しいな。

金野 祥久  konno@researchers.jp

Last modified: Thu Aug 3 09:32:47 JST 2000