8.0 file 入出力 < F >

file の入出力は、open 文 で開き、close 文で閉じる間の部分でできる。 通常の file は、<> を用いて標準入出力で行えば良いが、(1) 2 つ以上の file から入力する。(2) 名前がわかっている file から入力する。(3) cp コマンドの様に、file 名を引数にする場合があるから必要である。
(例題 8.0) file.input から データを読み込み、file.output に結果を 印刷する例を示す。(p8-0.pl)
#!/usr/local/bin/perl
open(IN,"< p-8.input");    # p-8.input から読むことを IN と定義する。
open(OUT,"> p-8.output");  # p-8.output に強制的に書くことを OUT と定義する。
while( < IN > ) {          # IN からのデータ $_ がある限り、以下を実行。
print OUT $_ ; }           # OUT に $_ を印刷。$_ は省略できる。
close(OUT);                # while の操作後 に OUT を閉じる。 
close (IN);                # IN も閉じる。

注意: 上のプログラムでは、 < IN > と space を開けているが、これは Mosaic の 表示を正しくするためで、 実際には space を開けてはいけない。

IN や OUT は ファイル・ハンドル (車のハンドルと同じ)と呼び、 変数と区別するために 大文字で書く。名称は自由に定めることが できる。open の中は、unix で用いられる、リダイレクション ( >, <, >>, >! ) や パイプ ( | ) が使える。unix のコマンドも 使える。

8.1 コマンドからの file 名入力の方法

perl を unix の 1つのコマンドとして使う場合、option ( -a, -o file, -help) を用いて機能を選ぶことが必要になる。この方法を説明しよう。
(例題 8.1) p8-1.pl は、cat と同じ機能をするが、以下の option を選べる。

-v で現在のバージョンを示す
-h で使い方を示す
-o file で出力先 file を示す。

#!/usr/local/bin/perl
$VER = "1.001";            # プログラムの version を示す変数。
$argv = join(' ',@ARGV);   # 念のためコマンド行を $argv に join して保存
while ($ARGV[0] =~ /^-/ )  # 入力の option -.* が無くなるまで実行
{ $_ = shift;              # 一文字取り出して、
if (/^-v$/) {              # もし -v であれば
die "version is $VER.\n"; }# version を表示して中断。die は Perl の終了。
elsif(/^-(h|help)$/) {     # さもなくば -h であれば、-help も可。
die "Usage: p8-1.pl file -o file.out\n"; } # 使い方を示し中断。
elsif(/^-o$/) {            # さもなくば -o であれば、
$outfile = shift; }        # 次の文字を 出力 file とする。
else {                     # それ以外の option は正しくない。ので
print "Usage: p8-1.pl file -o file.out\n"; # 使い方を示す。
die "Unrecognised option: $_\n"; } # 理解できなかった option を示し終了
}                          # while の終了。
# @ARGV には、最後に表示されるべき 入力 file 名がある。
# ここではそれが、複数あると仮定して、7.1 で使った foreach 
# を使って処理する。
# 出力先の設定をする。もし $outfile があれば、それに出力
if ($outfile) { open(OUT,"> $outfile") } 
# さもなくば 標準出力 STDOUT (予約語) に出力
else { open(OUT,">- "); } # >- は標準出力 を意味する。
# 以下の複数の 入力 file に関して、
foreach $file (@ARGV) {
open(IN,"< $file");    # 入力先を IN で定義
while(< IN >){print OUT;}# IN からの入力をそのまま印刷
close(IN)              # open した IN を、close (忘れずに!)
}                      # foreach を終了。
close(OUT)             # OUT を close

注意 : < IN > と space を開けているが、これは Mosaic の 表示 を正しくするためで、実際には space を開けてはいけない。

以下を実行してみよ。

% p8-1.pl -v
% p8-1.pl -h
% p8-1.pl -help
% p8-1.pl -hh
% p8-1.pl p-8.input
% p8-1.pl -o toto p-8.input

少し長いプログラムの例題であるが、実用性は高い。while() {print;} は、print ; と省略できる。print は変数だけでなく 配列も印刷できるので print ; は IN で読む全てのデータがはいる。1 行だけ読み込みたい場合には、{$_ = ; print; } とするか、print scalar; とすれば良い。scalar は 配列を変数に変換するので、最初の1行が変数に代入される。

8.2 Unix コマンドとの接続。

open 文は、"..." の中に unix のコマンドを入れることができるので、 いろいろ使うことができる。
(例題8-2) % cat file | sort -n -r の処理を perl の中で実行する。(p8-2.pl)
 
#!/usr/local/bin/perl
$file = shift;        # 最初の引数を $file とする。
open(IN,"< $file");   # $file を open する。
$a .= $_ while(< IN >); # sort するために IN を全てをつなげ $a に代入。
close(IN);            # close を忘れずに。
#
open(SORT,"|sort -n -r");# ファイルハンドル SORT を定義する。
print SORT $a;        # $a を SORT に 印刷することで sort が実現。
close(SORT);          # close を忘れずに。

注意 : < IN > と space を開けているが、これは Mosaic の 表示 を正しくするためで、実際には space を開けてはいけない。

例えば % p8-2.pl p8-2.dat を実行してみよ。

この例題は、あまりおもしろい例ではない。csh でできることは csh でするのがいちばんである。Perl の中でこのようなことをする場合には、 (1)中でいろいろ処理をしたい場合、(2) ひとつのコマンドにしてしまいたい場合。 (3) 2 つの file を同時に読み込んで、比べながら処理をする場合には有効である。perl のなかで csh を動かすのには、system という関数もある。 perl のなかで csh を動かすか、csh のなかで perl を動かすかは、自由である。両方できるのが、perl 言語に自由度があることを示している。