binmode は、UNIX では何の影響もなく、DOS で
は必須かもしれません。FILEHANDLE が式である場合には、その式の値がファイ
ルハンドルの名前として使われます。
open が自動的に close を行な
いますので、close filehandle する必要はありません。
(open() 参照。)ただし、明示的にクローズを行なったときにのみ入力ファ
イルの行番号 ($.) のリセットが行なわれ、open() によって行なわれる
暗黙の close では行なわれません。また、後でパイプの出力を見たい場
合のために、パイプのクローズでは、パイプ上で実行されているプロセスの完了
を待ちます。明示的なパイプのクローズはまた、コマンドのステータス値を $?
に設定します。例:
open(OUTPUT, '|sort >foo'); # sort へのパイプ ... # 出力 close OUTPUT; # sort の完了を待つ open(INPUT, 'foo'); # 結果を入力
filehandle は、実際のファイルハンドル名を値とする式でもかまいません。
untie() 関数にとって代わられました。]
DBM ファイルと連想配列の連結をはずします。
dbm(3) ファイルまたは ndbm(3) ファイルを連想配列に結び付けます。
assoc は、その連想配列の名前です。(普通の open とは違って、
最初の引数はファイルハンドルではありません。まあ、似たようなものですが。)
dbname は、データベースの名前です (拡張子の .dir や .pag はつけま
せん)。データベースが存在しなければ、mode (を umask() で修
正したもの) で指定されたモードで作られます。古い DBM 関数のみをサポート
しているシステムでは、プログラム中で 1 度だけ dbmopen() を実行す
ることができます。DBM も ndbm も持っていないシステムでは、
dbmopen() を呼び出すと致命的エラーになります。
DBM ファイルに対して、書き込み権が無いときには、連想配列を読みだすことだ
けができ、設定することはできません。書けるか否かを調べたい場合には、ファ
イルテスト演算子を使うか、エラーをトラップしてくれる、eval() の中
で、ダミーのエントリを設定してみることになります。
大きな DBM ファイルを扱うときには、keys() や values() のよ
うな関数は、巨大は配列を返します。大きな DBM ファイルでは、each()
関数を使って繰り返しを行なった方が良いかもしれません。例:
# history ファイルのオフセットを印字
dbmopen(%HIST,'/usr/lib/news/history',0666);
while (($key,$val) = each %HIST) {
print $key, ' = ', unpack('L',$val), "\n";
}
dbmclose(%HIST);
ungetc() を行ないますの
で、対話型の場合には、それ程有用ではありません。)引数を省略した
eof は、最後に読み込みを行なったファイルの EOF 状態を返します。空
の括弧 () は、コマンドラインのファイルリストで構成される、擬似ファイルを
示すために用いられます。つまり eof() は、while (<>) ループ
の中で、最終ファイルの最後を検出するために使えます。while (<>) ルー
プの個々のファイルを調べるには、eof(ARGV) か、括弧なしの
eof を用います。例:
# 最後のファイルの最終行の前にダッシュを入れる
while (<>) {
if (eof()) {
print "--------------\n";
}
print;
}
# ファイルごとに行番号をリセットする
while (<>) {
print "$.\t$_";
if (eof) { # eof() ではない
close(ARGV);
}
}
現実的なヒント: Perl で eof が必要となることは、ほとんどありませ
ん。データがなくなったときに、入力演算子が未定義値を返してくれるからです。
use Fcntl;
と書くことが必要でしょう。引数の処理と返却値については、下記の ioctl() と同様に動作します。fcntl(2)がインプリメントされていないマシンでは、 fcntl() は致命的エラーを引き起こします。使用例:
use Fcntl; fcntl($filehandle, F_GETLK, $packed_return_buffer);
select() に対す
る、ビットマップを構成するときに便利です。filehandle が式であれば、
その値がファイルハンドルの名前として使われます。
$LOCK_SH = 1;
$LOCK_EX = 2;
$LOCK_NB = 4;
$LOCK_UN = 8;
sub lock {
flock(MBOX,$LOCK_EX);
# さらに、待っている間に書き足した
# 人がいるといけないので ...
seek(MBOX, 0, 2);
}
sub unlock {
flock(MBOX,$LOCK_UN);
}
open(MBOX, ">>/usr/spool/mail/$ENV{'USER'}")
or die "Can't open mailbox: $!";
lock();
print MBOX $msg,"\n\n";
unlock();
flock() ではネットワークをまたがって、ロックは行なえません。この
ためには、fcntl() を使ってロックしなくてはなりません。
format が使用する内部関数ですが、直接呼び出すこともできま
す。これは、picture の内容にしたがって、list の値を整形し
(See section フォーマット文,を参照してください)、結果をフォーマット出力アキュ
ムレータ $^A に納めます。最終的に、write() がなされると、$^A の中
身が、何らかのファイルハンドルに書き出されますが、自分で $^A を読んで、
$^A の内容を "" に戻してもかまいません。format は通常、1 行ごと
に formline() を行ないますが、formline() 関数自身は、
picture の中にいくつの改行が入っているかは、関係がありません。ダブ
ルクォートで picture を囲む場合には、"@" という文字が配列名の始ま
りと解釈されますので、注意してください。
formline() は常に「真」を返します。
require "ioctl.ph"; # たぶん /usr/local/lib/perl/ioctl.ph
としなくてはならないでしょう。ioctl.h がないか、間違った定義をしている場
合には、<sys/ioctl.ph> のような C のヘッダファイルをもとに、自分で作らな
ければなりません。(これを手助けしてくれる、h2ph という Perl スクリプトが
Perl の配布キットに入っています。) function に応じて scalar
が読み書きされます。scalar の文字列値へのポインタが、実際の ioctl
コールの 3 番目の引数として渡されます。(scalar が文字列値を持って
おらず、数値を持っている場合には、文字列値へのポインタの代わりに、その値
が渡されます。このことを保証するためには、使用する前に scalar に 0
を足してください。) ioctl() で使われる構造体の値を操作するには、
pack() 関数と unpack() 関数が便利です。以下の例は、1 文字
削除の文字として DEL を指定します。
require 'ioctl.ph';
$sgttyb_t = "ccccs"; # 4 つの char と 1 つの short
if (ioctl(STDIN,$TIOCGETP,$sgttyb)) {
@ary = unpack($sgttyb_t,$sgttyb);
$ary[2] = 127;
$sgttyb = pack($sgttyb_t,@ary);
ioctl(STDIN,$TIOCSETP,$sgttyb)
|| die "Can't ioctl: $!";
}
ioctl (と fcntl) の返却値は、
OS からの返却値 | Perl の返却値
-------------------+-----------------------------
-1 | 未定義値
0 | "0 but true" という文字列
その他 | OS からの返却値
のようになっています。
つまり Perl は、成功時に「真」、失敗時に「偽」を返すことになり、OS が実 際に返した値も、
($retval = ioctl(...)) || ($retval = -1); printf "System returned %d\n", $retval;
のように簡単に知ることができます。
IPC::Open2 や IPC::Open3 が使えます。) "-"
を open すると STDIN がオープンされ、">-" を open すると
STDOUT がオープンされます。open は、成功時には、ゼロ以外を返し、
失敗時には未定義値を返します。パイプに関る open のときには、返却
値はサブプロセスの pid となります。例:
$ARTICLE = 100;
open ARTICLE or die "Can't find article $ARTICLE: $!\n";
while (<ARTICLE>) {...
open(LOG, '>>/usr/spool/news/twitlog'); # (log は予約語)
open(article, "caesar <$article |"); # 記事の復号
open(extract, "|sort >/tmp/Tmp$$"); # $$ は現 pid
# include を使っているファイルのリストを処理する
foreach $file (@ARGV) {
process($file, 'fh00');
}
sub process {
local($filename, $input) = @_;
$input++; # マジカルインクリメント
unless (open($input, $filename)) {
print STDERR "Can't open $filename: $!\n";
return;
}
while (<$input>) { # 間接ファイルハンドル
if (/^#include "(.*)"/) {
process($1, $input);
next;
}
... # 好きな処理
}
}
Bourne シェルの慣例にしたがって、expr の先頭に ">&"を付けると、 expr の残りの文字列をファイルハンドル名(数字であれば、ファイル記述 子) と解釈して、それを dupしてオープンします。"&" は、">"、">>"、"<"、 "+>"、"+>>"、"+<" というモード指定に付けることができます。指定するモード 指定は、もとのファイルハンドルのモードと合っていないといけません。STDOUT と STDERR をいったん保存し、リダイレクトし、元に戻すスクリプトを示します。
#!/usr/bin/perl open(SAVEOUT, ">&STDOUT"); open(SAVEERR, ">&STDERR"); open(STDOUT, ">foo.out") || die "Can't redirect stdout"; open(STDERR, ">&STDOUT") || die "Can't dup stdout"; select(STDERR); $| = 1; # バッファリングしない select(STDOUT); $| = 1; # バッファリングしない print STDOUT "stdout 1\n"; # これはサブプロセス print STDERR "stderr 1\n"; # でも働きます close(STDOUT); close(STDERR); open(STDOUT, ">&SAVEOUT"); open(STDERR, ">&SAVEERR"); print STDOUT "stdout 2\n"; print STDERR "stderr 2\n";
N を数値として、"<&=N" と指定すると、Perl は、そのファイル記述子に対する C の fdopen() と同じことを行ないます。たとえば:
open(FILEHANDLE, "<&=$fd")
"-|" や "|-" というふうに、"-" というコマンドにパイプをオープンすると、
fork が行なわれ、open の返却値として、親プロセスにはチャイ
ルドプロセスの pid が、チャイルドプロセスには 0 が返されます。(open が成
功したかどうかは、defined($pid) のようにして調べることができます。)
親プロセスでは、このファイルハンドルは通常通りに動作しますが、行なわれる
入出力は、チャイルドプロセスの STDIN/STDOUT にパイプされます。チャイルド
プロセス側では、そのファイルハンドルはオープンされず、入出力は新しい
STDOUT か STDIN に対して行なわれます。これは、setuid で実行して、シェル
コマンドのメタ文字を検索させたくないような場合に、パイプコマンドの起動の
仕方を制御したいとき、普通のパイプの open と同じように使います。
以下の組み合わせは、だいたい同じものです:
open(FOO, "|tr '[a-z]' '[A-Z]'"); open(FOO, "|-") || exec 'tr', '[a-z]', '[A-Z]'; open(FOO, "cat -n '$file'|"); open(FOO, "-|") || exec 'cat', '-n', $file;
パイプのファイルハンドルを明示的に close することで、親プロセスは、
チャイルドプロセスの終了を待ち、$? にステータス値を返します。注:
fork を行なう操作では、フラッシュされていないバッファがあると、
fork 後には、そのバッファの内容が両方のプロセスで残ったままになっ
てしまいますから、出力がダブらないように $| を設定する必要があるかもしれ
ません。
オープンするために渡されたファイル名は、はじめと終わりの空白が取り除かれ ます。妙な文字が含まれているようなファイル名をオープンするには、次のよう にして、最初と最後の空白を保護します:
$file =~ s#^(\s)#./$1#; open(FOO, "< $file\0");
select() を参照) に出
力します。list も省略すると、$_ を STDOUT に出力することになります。
デフォルトの出力チャネルを STDOUT 以外にしたければ、select 演算子
を使ってください。print の引数は list です。list の中
のものは、すべてリストコンテキストで評価されます。サブルーティンの呼び出
しがあれば、リストコンテキストでは、複数の値を返すかもしれません。また、
すべての引数を括弧で括るのでなければ、print というキーワードの次
に開き括弧を書いてはいけません。print と引数の間に "+" を書くか、
すべての引数を括弧で括ってください。
print filehandle sprintf(list) と等価です。list
の最初の要素は、printf フォーマットと解釈されます。
undef を返します。scalar は、実際に読み込んだ長さに応じて、
伸び縮みします。offsetを指定すると、scalar の先頭以外の場所
から、読み込みを行ないうことができます。この関数は、stdio ライブラリの
fread() 関数を使ってインプリメントしています。実際のシステムコールを利用
するには、sysread() を参照してください。
write や print を行なった場合のデフォルトが、この
filehandle になります。もう一つは、出力関連の変数への参照は、この
出力チャネルを参照するようになります。たとえば、複数の出力チャネルに対し
て、ページ先頭フォーマットを設定しなければならないのであれば、
select(REPORT1); $^ = 'report1_top'; select(REPORT2); $^ = 'report2_top';
のようにしなければならないでしょう。
filehandle は、実際のファイルハンドルの名前を示す、式でもかまいま せん。つまり、
$oldfh = select(STDERR); $| = 1; select($oldfh);
のようなものです。
Perl 5 では、ファイルハンドルはメソッドを持ったオブジェクトですから、最 後の例は
use FileHandle; STDERR->autoflush(1);
のように書くと良いでしょう。
fileno() と vec() を使って、
$rin = $win = $ein = ''; vec($rin,fileno(STDIN),1) = 1; vec($win,fileno(STDOUT),1) = 1; $ein = $rin | $win;
のようにして作成することができます。
複数のファイルハンドルに select を行ないたいのであれば、
sub fhbits {
local(@fhlist) = split(' ',$_[0]);
local($bits);
for (@fhlist) {
vec($bits,fileno($_),1) = 1;
}
$bits;
}
$rin = &fhbits('STDIN TTY SOCK');
のようなサブルーティンを書くとよいでしょう。
通常は、
($nfound,$timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
のように使い、いずれかの準備が整うまでブロックするには、
$nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
のようにします。どのビットマスクにも undef を設定することができま
す。timeout を指定するときは、秒数で指定し、少数でかまいません。注:
すべてのインプリメンテーションで、$timeleft が返せるものではありません。
その場合、$timeleft には、常に指定した timeout と同じ値が返されま
す。
250 ミリ秒の sleep と同じ効果が、
select(undef, undef, undef, 0.25);
のようにして得られます。(マイクロ秒じゃないよ :-))
undef が返されます。scalar は、実際に読み込んだ長さに応じて、
伸び縮みします。offset を指定すると、scalar の先頭以外の場所
から、読み込みを行ないうことができます。
select() 関数の項を参照) のフォーマットは、
その名前を明示的に、変数 $~ に代入することで、変更が可能です。
ページの先頭の処理は、自動的に行なわれます。現在のページに整形されたレコー ドを出力するだけのスペースがない場合には、改ページを行なってページを進め、 新しいページヘッダを整形するため、ページ先頭フォーマットが使われ、その後 でレコードが書かれます。デフォルトでは、ページ先頭フォーマットは、ファイ ルハンドルの名前に "_TOP" をつなげたものですが、ファイルハンドルが選択さ れている間に、変数 $^ に名前を設定すれば、動的にフォーマットを変更するこ とができます。そのページの残り行数は、変数 $- に入っており、この変数を 0 に設定することで、強制的に改ページを行なうことができます。
filehandle を指定しないと、出力はその時点のデフォルト出力チャネル
に対して行なわれます。これは、スクリプトの開始時点では STDOUT ですが、
select() 演算子で変更することができます。filehandle が
expr ならば、式が評価され、その結果の文字列が実行時に
filehandle の名前として見られます。フォーマットについて、さらには、
See section フォーマット文,を参照してください。
残念ながら、write は read の反対のことをするものではありま
せん。
Go to the first, previous, next, last section, table of contents.