perlでCGIを書く(4)
ファイル制御
CGIがJavaScriptと大きく異なる点は、サーバーにあるファイルをデータベースとして自由に開閉・読み書きできることです。これにより、掲示板など大量の情報を閲覧者すべてが共有することができるのです。
STDIN, STDOUTは、perlがデフォルトで用意したファイルハンドルです。
a) open(FILE, "> $file"); → 上書き
それまであった$fileの中身は消失し、新たな出力で書き替えられます。
b) open(FILE, ">> $file"); → 追加書き
既存の内容を$fileに残したまま、末尾に新たな出力が書き加えられます。
c) open(CMD, "| $cmd"); → 出力をコマンドに渡す
print CMD が発行されるごとに、出力が$cmdに対する入力になります。コマンドはCMDをcloseした後で実行されます。
ディレクトリの開閉にはopendir(), closedir(), readdir()などの関数が用意されています。
ファイルハンドルを省略した場合は特殊配列@ARGVの各要素が$ARGVにセットされ、ARGVがデフォルトファイルハンドルとして使用されます。このとき@ARGVが空だと$ARGV[0]にSTDINがセットされるので、結果STDINを読み込むことになります。難しい話でしたら忘れてください。
glob()関数はperl5から導入された機能ですが、これは従前のファイル名グロブ演算子<>が行入力演算子<>と混同されやすい、という理由によるものです。
上記とは全く別のアプローチもあります。
すごい名前の変数が並んでいますが、すべて暗記する必要はないでしょう。
(1) ファイルハンドル
ファイルにアクセスする際の識別子。名前は自由に付けられますが、全て大文字で書くのが慣例です。STDIN, STDOUTは、perlがデフォルトで用意したファイルハンドルです。
open(FILE, "< $file");
while(<FILE>) {
print;
}
close(FILE);
複数のファイルを制御する場合、ファイルごとに異なるファイルハンドルが必要です。
open(FILE, "> $file");
open(TMP, "< $tmp");
while(<TMP>) {
print FILE $_;
}
close(FILE);
close(TMP);
同じファイルにアクセスしても、入力と出力では別なファイルハンドルが必要です。open(IN, "< $dat"); $count = <IN> close(IN); $count++; open(OUT, "> $dat"); print OUT $count; close(OUT);select(ファイルハンドル) で、出力先のファイルハンドルを指定できます。
open(FILE, "> $log");
open(TMP, "< $tmp");
select(FILE);
while(<TMP>) {
print;
}
select(STDOUT);
close(FILE);
close(TMP);
(2) 出力に関わる指定
open()で出力の際、上書きか追加書きかを指定することができます。また、パイプの使用で入出力をコマンドの入出力に切り替えることができます。a) open(FILE, "> $file"); → 上書き
それまであった$fileの中身は消失し、新たな出力で書き替えられます。
b) open(FILE, ">> $file"); → 追加書き
既存の内容を$fileに残したまま、末尾に新たな出力が書き加えられます。
c) open(CMD, "| $cmd"); → 出力をコマンドに渡す
print CMD が発行されるごとに、出力が$cmdに対する入力になります。コマンドはCMDをcloseした後で実行されます。
(3) ディレクトリハンドル
opendir()でディレクトリにアクセスする際に必要ですが、考え方はファイルハンドルと同じです。ディレクトリの開閉にはopendir(), closedir(), readdir()などの関数が用意されています。
(4) 行入力演算子
<ファイルハンドル>と書きます。ファイルハンドルが指すファイルから、次の行を読み込んで返します。open(IN, "< ./count.dat"); $count = <IN>; close(IN);リストコンテキストで評価した場合は、ファイルの残りの各行を要素としたリストを返します。
open(LOG, "< ./log.dat"); @log = <LOG>; close(LOG);単純にSTDINを読み取る場合、デフォルトを指定する意味でファイルハンドルを省略します。
print while <>;<>をダイヤモンド演算子と呼びますが、私はこれをタマネギ演算子と呼んでしまいます。漫画「パタリロ!」に出てくるキャラクターの口を思い出すのが理由です(笑)。
ファイルハンドルを省略した場合は特殊配列@ARGVの各要素が$ARGVにセットされ、ARGVがデフォルトファイルハンドルとして使用されます。このとき@ARGVが空だと$ARGV[0]にSTDINがセットされるので、結果STDINを読み込むことになります。難しい話でしたら忘れてください。
(5) ファイル名グロブ
シェルのファイル名パターンを使い、ファイルの一覧を取得する機能。指定されたパターンにマッチするファイル名のリストを返します。
@files = glob("*");
foreach(@files) {
print "$_\n";
}
上記の例ではカレントディレクトリのすべてのファイルをリスト表示しますが、(" ")内に特定のパターンを指定することもできます。
@files = glob("*.txt");
.txtを拡張子に持つファイルのリストを返します。glob()関数はperl5から導入された機能ですが、これは従前のファイル名グロブ演算子<>が行入力演算子<>と混同されやすい、という理由によるものです。
上記とは全く別のアプローチもあります。
$dlist = `ls -l *.html`; print $dlist;バッククォートでlsコマンドを実行し、その際に.htmlを拡張子に持つファイルの一覧表示を指定します。コマンドが返す値は$dlistに格納されるので、単純に表示します。
(6) ファイルハンドルごとの特殊変数(主なものを抜粋)
| $| → | 0以外の値にセットすると、writeやprintを実行する度に出力バッファの内容を出力(フラッシュ)します。 |
| $% → | writeを使ったフォーマット出力において、現在のページ番号が格納されます。 |
| $= → | writeを使ったフォーマット出力において、ページ当りの行数。 |
| $- → | writeを使ったフォーマット出力において、現在のページの残り行数。 |
| $~ → | selectで選択された出力用ファイルハンドルに設定されているフォーマット名。 |
| $^ → | selectで選択された出力用ファイルハンドルに設定されているページ先頭フォーマット名。 |
| $* → | 1を設定すると、文字列が複数の行を含んでいるものとみなしてパターンマッチを行います。 |
| $_ → | 入力やパターンマッチでデフォルト対象となるスカラー変数。省略時に暗躍する謎の物体X。 |
| $. → | 最後に読み込んだファイルハンドルでの、現在の行番号。 |
| $/ → | 入力コードのセパレータ。デフォルトは改行コード。 |
| $\ → | print関数で最後に出力するセパレータ。 |
| $# → | print関数が数値を出力する際のフォーマット。 |
| $$ → | スクリプトが実行中のperlのプロセス番号。 |
| $? → | パイプ、`コマンド`、system関数の戻り値が格納されます。 |
| $0 → | 実行中のperlスクリプトのファイル名。 |
| $] → | 実行中のperlのバージョン。 |
| $! → | スカラーコンテキストではエラーメッセージ、リストコンテキストではerrnoの値が格納されます。 |
| $@ → | 最後に実行したeval関数が返す構文エラーメッセージを格納。 |
| $ARGV → | 現在<ARGV>から読み込んでいるファイルの中身が格納されます。 |
すごい名前の変数が並んでいますが、すべて暗記する必要はないでしょう。
[ CGI Top ]
[ BACK ]
[ Reference Top ]
[ NEXT ]
[ HOME ]