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.