インデックス
日本語 perl texinfo バージョン 4.0.19.2
この日本語 perl texinfo は、
基本的に perl 4.0 パッチレベル 19 のオンラインマニュアルを日本語訳し、
そのセクション分けに対応したノードに分割したものです。
関数の説明のノードなど、長すぎると判断したノードは、
私が勝手に分割しました。なお、関数の分類には、comp.lang.perl
に
流れていた Perl Reference Guide
を参考にしました。
ご覧になればおわかりのように、あちこちに ? マークや原文の引用があります。 これは、私が日本語に訳せなかったり、自信がなかったり、 訳せても意味が分からなかったりしたものです。 ご覧の皆様がこれらを一つでも減らすことにご協力いただければ非常に幸いです。
また、日本語訳にあたっては、たとえ日本語としてまずくても 技術的に間違っていない訳を目指したつもりですが、 私が UNIX を深く理解していないことからくる勘違いもあると思います。 この点も指摘いただければ幸いです。
では、perl life をお楽しみ下さい。
Copyright © 1990, 1991 高尾 直弥
"日本語 perl texinfo"は、フリーなドキュメントです。
perl と同様、GNU の General Public Licenses に従って修正・再配布して下さい。
GPL の詳細については、
添付した COPYING
というファイルを参照して下さい。
なお、これはお願いですが、このドキュメントに変更・改良を加えて 再配布する場合は、なるべく作者にもお知らせ下さい。
このドキュメントは高尾が個人の責任で作成したもので、会社は無関係です。
E-mail
: ntp@isl.mei.co.jp
勤務先 : 松下電器産業(株) 情報通信研究センター 情報システム研究所
(補足)
Perl Reference Guide
の作者は jv@mh.nl です。
'91 年 11 月 23 日の時点で、
最新版は Perl 4.0 patchlevel 10 に対応しているようです。
comp.lang.perl
にポストされた時のメッセージIDを以下に示します。
<1991Jul19.230410.18352@pronto.mh.nl> (アナウンス) <1991Jul19.231007.18647@pronto.mh.nl> (LaTex キット part 1 of 3) <1991Jul19.231102.18706@pronto.mh.nl> (LaTex キット part 1 of 3) <1991Jul19.231147.18765@pronto.mh.nl> (LaTex キット part 1 of 3) <1991Jul19.230642.18411@pronto.mh.nl> (PostScript キット part 1 of 4) <1991Jul19.230740.18470@pronto.mh.nl> (PostScript キット part 2 of 4) <1991Jul19.230831.18529@pronto.mh.nl> (PostScript キット part 3 of 4) <1991Jul19.230914.18588@pronto.mh.nl> (PostScript キット part 4 of 4)
また、comp.lang.perl
においては、
英語版 texinfo のアナウンスもポストされていますが、
この日本語 perl texinfo はそれとは独立に作成したものであり、
何の関係もありません。実際、セクション分け・関数の分類などが異なっています。
この texinfo は chem.bu.edu:/pub/perl-manual
から ftp できますし、
国内の FTP サイトにもアーカイブされています。
'91 年 11 月 23 日の時点で、
最新版は Perl 4.0 patchlevel 3 に対応しているようです。
謝辞
この日本語 perl texinfo を最初に fj.sources にポストしてから、 多くの方からアドバイス、改善案、訂正、励ましなどをいただきました。 ここにメールアドレスを挙げて、感謝の意を表します。
sawada@kimura2.kuee.kyoto-u.ac.jp (Akira SAWADA) t-nishim@dn.softbank.co.jp (Tetsuya Nishimaki) fukumoto@aa.cs.keio.ac.jp isoyama@rd.nttdata.jp (Hideyuki Isoyama) aisaka@west.cac.co.jp (Satoshi Aisaka) void@zorac.global.co.jp (Youichi Kusakabe) eiichi@mtl.t.u-tokyo.ac.jp (Eiichi Takahashi) masaka-t@ascii.co.jp (Masakazu "Paranoid" Takahashi) kusumi@isl.mei.co.jp
perl - Practical Extraction and Report Language
(抽出 & 報告用実用的言語)
使い方 : perl [オプション] ファイル名 引数
perl は任意のテキストファイルの走査、テキストファイルからの情報の取り出し、 その情報に基づいたレポートの出力のために最適化されたインタープリタ言語である。 また、システム管理作業の多くに適した言語でもある。 perl は美しい(小さい、エレガント、最小)というよりは 実用的(使いやすい、効率的、完全)である。
perl は C、sed、awk、sh の 最もよいところを結合したものである(作者の意向としては、であるが)ので、 これらの言語になじみのある人ならば perl を使うのは容易であろう。 (言語歴史学者なら csh、Pascal、さらには BASIC-PLUS の痕跡に気がつくだろう。) 表現法は C の表現法にそっくりである。
大半の UNIX のユーティリティとは違い、 perl はデータのサイズを制限しない -- メモリがあるかぎり。 perl はファイル全体を一つの文字列として読み込むことができる。 再帰の深さも制限されない。 連想配列で用いられるハッシュテーブルも必要に応じて大きくなる。 これはパフォーマンスを落とさないためである。
perl は大量のデータを迅速に走査するために 洗練されたパターンマッチのテクニックを使っている。 テキストを走査するのに最適化されてはいるが、perl はバイナリデータも扱えるし、 (dbm が使えるなら) dbm ファイルを連想配列そっくりの形で扱える。
データフロー追跡機構のおかげで 馬鹿らしいセキュリティホールを避けることができるので、 Setuid された perl スクリプトは C プログラムよりも安全である。
もし、通常なら sed や awk や sh を使うような問題だが しかしそれらには荷が重すぎる場合、またはもう少し早く走らせる必要があるが くだらないことを Cで書きたくはない場合、perl がぴったりだ。 sed や awk のスクリプトから perl スクリプトへの変換プログラムもある。
さて、宣伝はこれで充分だ。
起動時、perl は次の順序でスクリプトを探す。
-e
スイッチで 1 行ずつ指定するスクリプト。
#!
指定をサポートするシステムにおいては、
この方法でインタプリタが起動される)
-
を指定しなければならない。
スクリプトが見つかると、perl はそれを内部形式にコンパイルする。 スクリプトが文法的に正しければ、実行される。
1 文字オプションは次に続くオプションがあれば、それとくっつけてもよい。
特に #!
機構を使って起動する時は引数が一つしか許されないので、
便利である。
#!/usr/bin/perl -spi.bak # -s -p -i.bak と同じ ...
perl には以下のコマンドラインオプションがある。
-0
: レコードセパレータの指定-0 数字
レコードセパレータ($/
)を8進数で指定する。See $/.
数字を指定しない場合はヌルキャラクタがセパレータになる。 数字の前や後に他のスイッチがあってもよい。
例えば、ファイル名の最後にヌルキャラクタを付けてプリントする find
があるなら、次のように使える。
find . -name '*.bak' -print0 | perl -n0e unlink
00
は特殊な値で、perl はファイルをパラグラフモードで読み込む。
0777
を指定すると、
その値を持つ文字はないので perl は全ファイルを読み込む。
-a
: オートスプリットモード-a
-n
や -p
と一緒に用いて、
オートスプリットモードを ON にする。
-n
や -p
により自動的に行われる while
ループ内で、
最初に自動的に split
コマンドが実行される。
perl -ane 'print pop(@F), "\n";'
は次の例と同等である。
while (<>) { @F = split(' '); print pop(@F), "\n"; }
-c
: 文法チェック-c
スクリプトの文法をチェックし、実行せずに終了する。
-d
: デバッグモード-d
perl デバッガのもとでスクリプトを実行する。
Debugging
の章を参照のこと。
See Debugging.
-D
: デバッグフラグをセットする-D数字
デバッグフラグをセットする。
スクリプトがどのように実行されるかを見るには、
-D14
を使えばよい
(これはデバッグ情報をつけて perl をコンパイルした時にのみ動作する)。
-D1024
も有用な値である。
これを使うと、コンパイルされた文法ツリーをリストする。
また、-D512
を使うと、コンパイルされた正規表現を出力する。
-e
: コマンドラインからスクリプトを入力-e コマンドライン
1 行のスクリプトを入力するのに用いる。
複数行のスクリプトを指定するには -e
を複数指定すればよい。
-e
が指定されると、
perl は引数のリストからスクリプトファイル名を探さない。
-i
: 入力ファイルを修正し、バックアップファイルを作成する-i拡張子
<>
構造で処理されるファイルをその場で修正することを指定する。
入力ファイルの名前を変えて、出力ファイルを元の名前でオープンし、
print
文のデフォルトの出力ファイルとすることで処理する。
拡張子が与えられれば、バックアップファイルの名前として 元のファイル名にその拡張子を加えたものが使われる。
拡張子がなければ、バックアップはされない。
perl -p -i.bak -e "s/foo/bar/;"
... を実行することは
次のスクリプトと同じで、
#!/usr/bin/perl -pi.bak s/foo/bar/;
これは次のものと同等である。
#!/usr/bin/perl while (<>) { if ($ARGV ne $oldargv) { rename($ARGV, $ARGV . '.bak'); open(ARGVOUT, ">$ARGV"); select(ARGVOUT); $oldargv = $ARGV; } s/foo/bar/; } continue { print; # 元の名前のファイルに出力する } select(STDOUT);
ただし、-i
を用いた方法では
ファイル名がいつ変更されたかを調べるために $ARGV
と $oldargv
を
比較する必要がない点が異なる。-i
を用いた場合、
実際にセレクトするファイルハンドルとして ARGVOUT
を使っている。
STDOUT
がループの後で
デフォルトの出力ファイルハンドルに戻されている点に注意。
入力ファイルすべてに追加を行ったり、行番号をリセットしたりする場合、
各々の入力ファイルの終わりを知るために eof
を使うことができる。
(eof
での例を参照。See eof.)
-I
: C プリプロセッサにインクルードファイルの位置を知らせる-Iディレクトリ
-P
と一緒に用いて C プリプロセッサに
インクルードファイルの位置を知らせる。
デフォルトでは /usr/include
と /usr/lib/perl
を検索する。
-l
: 行末処理を自動的に行なう-l 8進数
行末処理を自動的に行う。二つの効果がある:
-n
または -p
と一緒に用いた場合、
行ターミネータを自動的に除く。
$\
に 8 進の値をセットし、
print 文が全て最後に行ターミネータをつけるようにする。
8 進数を省略すると、$/
の値を $\
にセットする。
例えば、行を 80 コラムに切り揃えるためには:
perl -lpe 'substr($_, 80) = ""'
注意:
$\ = $/
の代入はスイッチが処理される時に行なわれるので、
-l
の後に -0
がある場合、
入力レコードセパレータが出力レコードセパレータと違う値を持つ場合がある:
gnufind / -print0 | perl -ln0e 'print "found $_" if -p'
この場合は $\
を改行、$/
をヌルキャラクタにセットする。
See $backslash for $\
, and See $/.
-n
: sed -n や awk のエミュレート-n
スクリプトの前後に下に示すループがあるものとして perl を起動する。 こうすると、引数のファイル全部について繰り返しが行われる (sed -n や awk のように)。
while (<>) { ... # スクリプトがここにくる }
デフォルトでは入力行の出力がなされないことに注意。
出力したければ、-p
を用いる。
以下に示す例は一週間以上前のファイルを効率的に全て消去する方法である。
find . -mtime +7 -print | perl -nle 'unlink;'
こうすると find
の -exec
スイッチを使うよりも速い。
なぜなら、ファイル名が見つかるたびにプロセスを起動する必要がないからである。
-p
: sed のエミュレート-p
スクリプトの前後に下に示すループがあるものとして perl を起動する。 こうすると、引数のファイル全部について繰り返しが行われる(sed のように)。
while (<>) { ... # スクリプトがここにくる } continue { print; }
入力行が自動的に出力されることに注意。
出力しないようにするには -n
を用いる。
-p
は -n
に優先する。
-P
: コンパイル前に C プリプロセッサを通す-P
perl のコンパイルの前に C プリプロセッサを通す。
(perl のコメントも cpp
の命令も #
で始まるので、
コメントを C プリプロセッサが理解する単語、
例えば if
や else
や define
で
始めないようにしなければならない。)
-s
: コマンドラインオプションの解析結果を変数にセットする-s
コマンドラインのスクリプト名の後、
ファイル名の引数(または --
)の前のスイッチについて初歩的な解析を行う。
スイッチが見つかると、@ARGV
から除かれ、
対応する変数を perl スクリプト内でセットする。
次のスクリプトでは、-xyz
スイッチをつけてスクリプトを起動した時、
またその時のみ true
を出力する。
#!/usr/bin/perl -s if ($xyz) { print "true\n"; }
-S
: スクリプトを環境変数 PATH
を用いて探す-S
スクリプトを探すのに、環境変数 PATH
を用いる
(スクリプト名が /
で始まらないかぎり)。
これは特に #!
をサポートしないマシンにおいて #!
を
エミュレートするのに用いられる。その使い方は以下の通りである。
#!/usr/bin/perl eval "exec /usr/bin/perl -S $0 $*" if $running_under_some_shell;
システムは 1 行目を無視し、スクリプトを /bin/sh
に渡す。
/bin/sh
は perl スクリプトをシェルスクリプトとして実行しようとする。
シェルは 2 行目を通常のシェルコマンドとして実行し、
perl インタプリタを起動する。
システムによっては $0
は必ずしもフルパスを含まないので、
-S
を用いて perl に必要ならばスクリプトを探すように指示する。
perl がスクリプトを見つけると、解析を行い、
変数 $running_under_some_shell
が真になることはないので、
2 行目を無視する。
ファイル名に含まれるスペースなどを正しく扱うには、
$*
よりも $1+"$@"
のほうがよいだろうが、
csh が解釈する場合には動作しない。
sh ではなくて csh で起動するには、あるシステムでは #!
行を
コロンのみを含む行に書き換える必要があるかもしれない。
perl はこの行を無視する。その他のシステムではこの方法は使えず、
次のように、csh、sh、perl のどの下でも動作するような、
とてもややこしい方法をとる必要がある。
eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' & eval 'exec /usr/bin/perl -S $0 $argv:q' if 0;
-u
: スクリプトのコンパイル後、コアダンプする-u
スクリプトのコンパイルの後、コアダンプする。
このコアダンプから、undump
プログラム(提供していない)を用いて
実行可能ファイルに変換できる。こうすると、
ディスク消費が増えるかわりに(実行ファイルを strip
すれば最小にできる)
スタートアップが速くなる。(しかし、
私のマシンでは hello world
の実行形式が 200k の大きさになる。)
この実行形式を set-id プログラムとして走らせるのなら、
通常の perl ではなく taintperl
を用いてコンパイルした方が良い。
ダンプする前に実行したいスクリプトがある場合は、
代わりに dump
コマンドを使えばよい。
注意 : undump
が使えるかどうかはプラットフォームによるので、
マシンによっては利用できないものもある。See dump.
-U
: 安全でない操作を可能にする-U
安全でない操作を可能にする。
現在の所、"安全でない"操作とは、スーパーユーザの権限で走らせている際
にディレクトリを unlink
すること、および"汚れ"チェックの結果、
警告が出るような setuid プログラムを走らせることだけである。
-v
: perl のバージョンとパッチレベルを表示する-v
perl のバージョンとパッチレベルを出力する。
-w
: 識別子に関するさまざまな警告を出す-w
識別子について以下の場合に警告を出す。
==
を数値ではなさそうな値に用いている
-x
: スクリプトがメッセージ内に埋め込まれていることを知らせる-xディレクトリ
スクリプトがメッセージ内に埋め込まれていることを perl に知らせる。
#!
で始まり、
perl
という文字列を含む最初の行が現れるまでのゴミは無視される。
その行に指定した意味のあるスイッチはすべて適用される
(ただし通常の #!
処理と同じく、スイッチのかたまりひとつだけである)。
ディレクトリ名を指定すると、 perl はスクリプトを実行する前にそのディレクトリに移る。
-x
は先頭のゴミのみを捨てる。
スクリプトの後にゴミがある場合は、
スクリプトを __END__
で終わらなければならない
(望むなら、スクリプトで後ろのゴミの一部または全部を
ファイルハンドル DATA
経由で処理することは可能である)。
See String literals for __END__
.
perl には 3 種類のデータ型 : スカラー、スカラー配列、および連想配列がある。 通常の配列は添え字が数字だが、連想配列の場合は文字列である。
perl における演算や値の解釈は、 演算や値のコンテキストからの要求に依存することがある。 主なコンテキストには 3 つ : 文字列、数値、および配列がある。 演算の中には、配列を要求するコンテキストでは配列を、 そうでなければスカラー値を返すものがある。 (そのような演算子についてはそのドキュメントに記述されている。) スカラー値を返す演算子は、 コンテキストが文字列あるいは数値のどちらを要求しているかは考慮しないが、 スカラー変数およびスカラー値は 文字列あるいは数値のコンテキストのふさわしい方に解釈される。 スカラーはそれがヌル文字列あるいは 0 でなければ論理的に真であると解釈される。 演算子が返す論理値は真の場合は 1、 偽の場合は 0 または ´´(ヌル文字列)である。
実は、ヌル文字列には 2 種類ある。
define されたもの、undefined のものである。
undefined のヌル文字列はエラーや、end of file や、
初期化されていない変数や配列要素を参照しようとした時など、
実際の値が存在しない時に返る。
undefined ヌル文字列は最初にそれにアクセスすることにより、
defined になることがあるが、その前に defined()
演算子を用いて
値が defined かそうでないかを知ることができる。
スカラー変数への参照は、それが配列の一部であっても、
常に $
で始める。すなわち、以下の通りである。
$days # 単純なスカラー変数 $days[28] # 配列 @days の 29 番目の要素 $days{'Feb'} # 連想配列の値の一つ $#days # 配列 @days の最後の添え字
しかし、配列全部や一部の取り出しなどは '@' で始める。
@days # ($days[0], $days[1],... $days[n]) @days[3,4,5] # @days[3..5] と同じ @days{a,c} # ($days{'a'},$days{'c'}) と同じ
そして連想配列全部を扱うには、'%' で始める。
%days # (key1, val1, key2, val2 ...)
これら 8 つはすべて左辺値として扱うことができる。すなわち、代入可能である。
(さらに、あるコンテキストでは代入操作自体も左辺値となりうる。
s
、tr
および chop
における例を参照のこと。)
See s/PATTERN/REPLACEMENT/,
See tr/SEARCHLIST/REPLACEMENTLIST/, and See chop.
スカラーへの代入を行うと、右辺をスカラーのコンテキストで評価するのに対し、 配列や配列の一部への代入は右辺を配列のコンテキストで評価する。
配列 @days
の長さを、csh のように、
$#days
で評価することができる(実際には、配列の長さではなく、
最後の要素の添え字である。なぜなら、通常 0 番目の要素があるからである)。
$#days
へ代入すると、配列の長さが変わる。
この方法により配列を小さくしても、実際には値は何も破壊されない。
すでに小さくした配列を大きくすると、もともとあった要素が元に戻る。
また、大きくなりそうな配列をあらかじめ大きくしておくと、
効率をいくらか良くすることができる。(配列を大きくするには、
配列の最後を超える要素に代入を行う方法もある。この方法と、
$#whatever
へ代入する方法との違いは、
間の要素にヌルがセットされることである。)
配列の中身を捨てて空にするには、ヌルリスト ()
を代入すれば良い。
次の二つは全く同等である。
@whatever = (); $#whatever = $[ - 1;
配列をスカラーのコンテキストで評価すると、配列の長さが返る。 次の式は常に真である。
scalar(@whatever) == $#whatever - $[ + 1;
連想配列をスカラーのコンテキストで評価すると、 配列が要素を含む場合かつその場合に限り真の値を返す。 (要素がある場合に返る値は文字列で、 使用している bucket の数およびアロケートされている bucket の数からなり、 スラッシュで区切られている。)
多次元配列は直接はサポートしていないが、
連想配列を用いて
複数の添え字をエミュレートする方法については $;
変数の項を参照のこと。
また、多次元の添え字を 1 次元の添え字に変換するサブルーチンを書くこともできる。
See $;.
各々のデータ型に応じて、それぞれの名前空間がある。 衝突を心配することなく、同じ名前をスカラー変数、配列、連想配列、 ファイルハンドル、サブルーチン名、またはラベルにつけることができる。
変数や配列への参照は常に $
、@
、%
で始まるので、
予約語は変数名については実際には使用可能である。
(しかし、ラベルやファイルハンドルについては予約語は使用できない。
特殊な文字で始まらないからである。
ヒント: open(log,'logfile')
より open(LOG,'logfile')
を
使った方が良い。
大文字のファイルハンドル名を使うと、読み易さも向上し、
将来予約される単語との衝突も避けることができる。)
大文字小文字の区別は重要である -- FOO
、Foo
、foo
は
すべて異なる名前である。アルファベットで始まる名前は数字や下線を含んでもよい。
アルファベットで始まらない名前は 1 文字に限られる。
例: $%
や $$
。
(ほとんどの一文字名は perl の予約変数として意味がある。
Predefined Names
の項を参照。See Predefined Names).
数値文字列は通常の小数点や整数の形式で表す。
12345 12345.67 .23E-10 0xffff # 16 進 0377 # 8 進
文字列はシングルクォートまたはダブルクォートで区切られる。 これらはシェルにおけるクォートとよく似ている。 ダブルクォートで囲まれた文字列にはバックスラッシュや変数の置換が行われる。 シングルクォートで囲まれた文字列には行われない。( \' と \\ を除いて。)
通常のバックスラッシュ規則が改行やタブなどの文字を表すのに使える。 加えて以下のちょっと変わった形式も使える。
\t タブ \n 改行 \r リターン \f フォームフィード \b バックスペース \a アラーム(ベル) \e エスケープ \033 8 進文字 \x1b 16 進文字 \c[ コントロール文字 \l 次の文字を小文字にする \u 次の文字を大文字にする \L \E までを小文字にする \U \E までを大文字にする \E 大小文字の修飾の終り
改行を直接文字列に書き入れることもできる。 すなわち、文字列は始まった行と異なる行で終わることができる。 これは便利であるが、最後にクォートを忘れると、 クォートを含むかなり離れた別の行を見つけるまで perl は エラーを報告しないだろう。
文字列内の変数置換はスカラー変数・通常の配列値・配列の一部に限られる。
(言い換えると、$
や @
で始まる識別子と、
それに括弧で囲まれた添え字がある場合だけである。)
次のコードは The price is $100.
を出力する。
$Price = '$100'; # 解釈されない print "The price is $Price.\n";# 解釈される
注意:
後に続くアルファベットや数字と区別するために、
識別子を {}
で囲うことができる。
また、シングルクォートで囲まれた文字列は
その前の単語とはスペースで区切らなければならない。
なぜなら、シングルクォートは識別子として有効な文字だからである。
(Packages
の項を参照。See Packages.)
特殊な文字列が二つあり、__LINE__
と __FILE__
である。
これはプログラムのその時点での行番号とファイル名を表す。
これらは独立したトークンとしてのみ使用できる。
文字列中に書き入れることはできない。
さらに、__END__
は実際のファイルの終了の前の
スクリプトの論理的な終了を示すのに使える。
残りのテキストは全て無視される
(ただしファイルハンドル DATA
から読むことができる。)。
^D
と ^Z
の
二つのコントロールキャラクタは __END__
と同じ意味である。
文法的に解釈不可能な単語は
それがシングルクォートで囲まれているかのように扱われる。
このため、アルファベット・数字・下線のみからなる単語は
アルファベットで始まらなければならない。
ファイルハンドルやラベルと同じく、小文字のみからなる裸の単語は
将来の予約語と衝突する危険がある。-w
スイッチを使えば、
perl はそのような単語について警告する。
配列値をダブルクォートで囲まれた文字列に入れた場合は、
配列の全要素を $"
で示される区切り(デフォルトはスペース)
で区切って一つにした文字列になる。
(3.0 以前のバージョンの perl では @
は
メタキャラクターではなかったので、
@array
、$array[EXPR]
、@array[LIST]
、
$array{EXPR}
、@array{LIST}
の解釈は
プログラムのどこかで参照されているか、
予め define されている場合にのみ行われる。)
次の二つは同等である。See $dquote for $"
.
$temp = join($",@ARGV); system "echo $temp"; system "echo @ARGV";
検索パターン(これにもダブルクォートと同じ置換が行われる)においては、 あいまいな場合がある。
/$foo[bar]/
は
として解釈するべきか、/${foo}[bar]/
([bar]
は正規表現の文字クラス)
として解釈するべきか ?/${foo[bar]}/
([bar]
は配列@foo
の添え字)
@foo
が存在しないならば、明らかに文字クラスである。
@foo
が存在すれば、perl は [bar]
についてよく考え、
その答えはほとんどの場合正しい。もし間違った解釈をしたり、
あるいはあなたが単に偏執狂ならば、
上で述べたように {}
を入れることで正しい解釈をさせることができる。
行指向の引用法はシェルの同様の文法に基づいている。
<<
の後に引用文の終わりを示す文字列を指定すると、
現在行からその文字列が現れるまでの行全てがその値になる。
終わりを示す文字列は識別子でも、引用するテキストでもよい。
引用するテキストの場合、通常のクォーティングと同じく
クォートの種類がテキストの扱い方を決める。
クォートしない識別子はダブルクォートと同じように働く。
(スペースを入れた場合、それはヌル識別子として扱われ、これは有効で、
最初のブランクラインにマッチする。--
下の Merry Christmas
の例を見よ。)
終わりを示す文字列はそれだけで(クォートやスペースを回りにつけず)
存在しなければならない。
print <<EOF; # 前の例と同じ The price is $Price. EOF print <<"EOF"; # 上の例と同じ The price is $Price. EOF print << x 10; # ヌル識別子が終わりを示す文字列 Merry Christmas! print <<`EOC`; # コマンドを実行する echo hi there echo lo there EOC print <<foo, <<bar; # スタックに積むことができる I said foo. foo I said bar. bar
配列の表現は、個々の値をコンマで区切り、括弧 ()
で囲む:
(LIST)
配列値を要求しないコンテキストでは、C のコンマ演算子と同じく、 最後の要素の値が配列表現の値となる。例えば、
@foo = ('cc', '-E', $bar);
は配列 foo
に全配列値を代入するが、
$foo = ('cc', '-E', $bar);
は変数 bar
の値を変数 foo
に代入する。
注意: 変数として存在する(actual)配列のスカラーのコンテキストにおける値は
配列の長さである。次の例では $foo
に 3 を代入する。
@foo = ('cc', '-E', $bar); $foo = @foo; # $foo は 3 になる
配列表現の括弧を閉じる前に余分なコンマがあっても良い。 つまり、以下の表現は可能である。
@foo = ( 1, 2, 3, );
リストが評価される時は、 リストの要素はすべて配列のコンテキストで評価され、結果として得られる配列値は、 個々の要素がリストのメンバーであったかのようにリストに入れられる。 つまり、配列はリストにおいては区別がなくなる。リスト
(@foo,@bar,&SomeSub)
は @foo
, @bar
の全要素
および SomeSub
という名前のサブルーチンが返す全要素を含む。
リストの値は通常の配列と同様に添え字をつけて指定できる。
$time = (stat($file))[8]; # stat は配列値を返す $digit = ('a','b','c','d','e','f')[$digit-10]; return (pop(@foo),pop(@foo))[0];
配列のリストはその要素が全て左辺値であり、 かつその時にかぎり代入可能である。
($a, $b, $c) = (1, 2, 3); ($map{'red'}, $map{'blue'}, $map{'green'}) = (0x00f, 0x0f0, 0xf00);
最後の要素は配列又は連想配列であってもよい。
($a, $b, @rest) = split; local($a, $b, %rest) = @_;
実際にはリストのどこに配列を入れてもいいのだが、
リスト中の最初の配列が全ての値を取ってしまい、
その後の要素にはヌル値が入ってしまう。
これは local()
において便利かもしれない。(See local.)
連想配列の表現は、キー、値として解釈されるべき値のペアを含む。
# 上記の map への代入と同じ。 %map = ('red',0x00f,'blue',0x0f0,'green',0xf00);
スカラーのコンテキストでの配列の代入は 代入の右辺の expression により得られる要素の数を返す。
$x = (($foo,$bar) = (3,2,1)); # $x を 2 ではなく 3 にセットする
文字列を ``
で囲んだ場合、
まずダブルクォートと全く同じ変数置換が行われる。次にシェルの場合と同じく、
コマンドであると解釈され、そのコマンドの出力がこの擬似表現の値となる。
スカラーのコンテキストでは、全出力が入った 1 つの文字列が返る。
配列のコンテキストでは、出力の 1 行を 1 要素とした配列値が返る。
(他の行ターミネータを使う場合には $/
をセットする。)See $/.
コマンドは擬似表現が評価されるたびに実行される。
コマンドのステータスは $?
に返る。(See $?.)
csh の場合とは異なり、返ってくるデータには置換は一切行われない。--
改行は改行のままである。どのシェルとも異なり、
シングルクォートで囲んでもコマンド内の変数名は変換されてしまう。
$
をシェルに渡すには、バックスラッシュを使う必要がある。
<>
で囲んだファイルハンドルを評価すると、
そのファイルから次の行を読み込む
(改行を含むので、EOF
までは偽にならない。
このときは値として undefined
が返る)。
通常はその値を変数に代入する必要があるが、
一つだけ自動的に代入が行われる状況がある。
<ファイルハンドル>
のみが while
ループの条件である場合は、
(そしてこの場合にかぎり)値は変数 $_
に自動的に代入される。
(奇妙に思うかも知れないが、
これをほとんどの perl スクリプトにおいて使うであろう。)
とにかく、次の例は全て同等である。
while ($_ = <STDIN>) { print; } while (<STDIN>) { print; } for (;<STDIN>;) { print; } print while $_ = <STDIN>; print while <STDIN>;
ファイルハンドル STDIN
、STDOUT
、STDERR
は
予約されている。(stdin
、stdout
、stderr
でも動作するが、
パッケージの中ではグローバルではなくローカルな識別子として解釈されるので、
働かない。)
これら以外のファイルハンドルは open
関数を用いて作成する。
(See open.)
<ファイルハンドル>
を配列を要求するコンテキストで用いると、
全入力行の 1 行がそれぞれ 1 要素となる配列が返る。
この方法を使うと簡単に巨大なデータ空間を作ることができるので、
注意して使った方がいい。
ヌルファイルハンドル <>
は特殊で、
sed や awk の動作をエミュレートするのに用いる。
<>
には、標準入力か、
またはコマンドラインにリストアップした全ファイルから入力される。
これは次のように動作する。
<>
を最初に評価すると、配列 ARGV
がチェックされ、
ヌルであれば、$ARGV[0]
が -
にセットされる。
これは、オープンする時に標準入力となる。
次に配列 ARGV
がファイル名のリストとして処理される。次のループ
while (<>) { ... # 各行に対するコード }
は下と同等である。
unshift(@ARGV, '-') if $#ARGV < $[; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # 各行に対するコード } }
違いは、前者は後者ほど書くのが面倒でないということだけであり、
前者でも実際に配列 ARGV
をシフトし、
現在のファイル名を $ARGV
に代入している。
また、ファイルハンドル ARGV
を内部で用いている。
1 番目のファイル名を配列の最初に残しておくかぎり、
最初の <>
の前で @ARGV
に手を加えることができる。
行番号 ($.
) は入力が一つの大きなファイルであるのと同じく、
継続して増える。
(ファイル毎に行番号をリセットする方法については eof
の例を参照のこと。
See eof.)
@ARGV
にファイルのリストをセットしたい場合は、そうすればよい。
スクリプトにスイッチを渡したい場合は、
最初に次のようなループを入れればよい。
while ($_ = $ARGV[0], /^-/) { shift; last if /^--$/; /^-D(.*)/ && ($debug = $1); /^-v/ && $verbose++; ... # ほかのスイッチ } while (<>) { ... # 各行に対するコード }
<>
は一度だけ偽を返す。この後もう一度呼ぶと、
新たな @ARGV
リストの処理を行っているものと見なす。
そしてこの時 @ARGV
を
セットしていない場合は STDIN
から入力される。
<>
の中の文字列がスカラー変数を参照している場合
(例えば <$foo>
)、その変数は
入力が行われるべきファイルハンドルの名前を値として持つ。
<>
の中の文字列がファイルハンドルでない場合は、
置換されるべきファイル名パターンであると解釈され、
コンテキストによりファイル名の配列またはリスト内の次のファイル名が返る。
1 レベルの $
の解釈は最初になされるが、
上で述べたように <$foo>
は
間接的にファイルハンドルを指すので使えない。
強制的にファイル名置換と解釈させるためには、
{}
を入れればよい: <${foo}>
。
while (<*.c>) { chmod 0644, $_; }
は次と同等である。
open(foo, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|"); while (<foo>) { chop; chmod 0644, $_; }
実は、現在の所、後者の方法でインプリメントしている。
(つまり、マシン上に /bin/csh
がないかぎり
スペースなどを含むファイル名についてはうまく働かない。)
もちろん、上の操作を行う最も短い方法は
chmod 0644, <*.c>;
である。
perl スクリプトは一連の宣言とコマンドからなる。 perl において宣言する必要があるのは レポート・フォーマットとサブルーチンだけである。
これらについてはそれぞれ Formats
、
Subroutines
の項を参照のこと。
See Formats, and See Subroutines.
ユーザが作成した初期化されていないオブジェクトは
代入などの明示的な操作が行われるまで全てヌルまたは 0 となる。
コマンド群が入力行全てについて実行される sed や awk とは違って、
コマンド群は一度しか実行されない。
このため、入力ファイルの各行について繰り返しを行うには
明示的にループを設けなければならない一方、
着目するファイル、行をよりよくコントロールすることができる。
(実は、正しくない... -n
や -p
オプションを使って、
自動的にループさせることが可能である。See Option.)
宣言文はコマンドを書くことができる場所ならどこにでも書くことができ、 コマンド実行の基本的なシーケンスには影響を与えない。 つまり、宣言が影響を与えるのはコンパイル時だけである。 通常は全ての宣言をスクリプトの最初か最後のどちらかに書く。
perl は、ほとんど、フリーフォームの言語である。 (唯一の例外はフォーマットの宣言であるが、その理由は明白である。)
コメントは文字 #
から行の終わりまでである。
C のコメント /* */
を使うと、
コンテキストにより割り算もしくはパターンマッチングであると解釈されるので、
用いないように。
perl において、コマンド群を {}
で囲むと
一つのコマンドとして扱うことができる。これをブロックと呼ぶ。
次の複合コマンドはフローコントロールのために用いる。
if (EXPR) BLOCK if (EXPR) BLOCK else BLOCK if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK LABEL while (EXPR) BLOCK LABEL while (EXPR) BLOCK continue BLOCK LABEL for (EXPR; EXPR; EXPR) BLOCK LABEL foreach VAR (ARRAY) BLOCK LABEL BLOCK continue BLOCK
注意すべきことは、C や Pascal と違い、これらは文(statement)ではなく、
ブロックとして宣言されている点である。このため、{}
が必要となる。
条件文を {}
を使わずに書くためには、いくつか方法がある。
次の例は全て同じことをする。
if (!open(foo)) { die "Can't open $foo: $!"; } die "Can't open $foo: $!" unless open(foo); open(foo) || die "Can't open $foo: $!"; # foo or bust! open(foo) ? 'hi mom' : die "Can't open $foo: $!"; # a bit exotic, that last one
if
文は単純である。ブロックは必ず {}
で囲まれているので、
if
や else
がどこにかかるかについて曖昧になることはない。
if
の代わりに unless
を使う場合、テストの結果が逆に扱われる。
while
文は expression が真(ヌル文字列や 0 でない)である間、
ブロックを実行する。ラベルをつけてもよい。ラベルをつける場合、
その識別子の後にコロンをつける。
ラベルはループコントロール文 next
、last
、redo
の
ループを指定する(identifies the loop)(以下の例を参照。)。
continue
ブロックがあれば、条件文を再評価する直前に必ず実行される。
これは for
ループの 3 番目の条件と同様である。
このため、たとえループが next
文を通じて続行される場合でも、
ループ変数のインクリメントを行うために用いることができる。
(C の continue
文と同様。)
while
を until
で置き換えると、
テストの結果が逆に扱われるが、条件テストはループの最初にも行われる。
if
文や while
文において、
(EXPR)
をブロックで置き換えることができる。
この場合、条件はブロックの最後のコマンドの値が真ならば真となる。
for
ループは
それと対応する while
ループと全く同様に動作する。
for ($i = 1; $i < 10; $i++) { ... }
は次と同じである。
$i = 1; while ($i < 10) { ... } continue { $i++; }
foreach
ループは通常の配列値について、
順にその要素を変数にセットしながら繰り返しを行う。
変数は暗黙的にループにローカルで、ループを抜けると元の値に戻る。
実はキーワード foreach
は for
と全く同じものなので、
読み易さで foreach
、簡潔さで for
を使うことができる。
変数名を省略すると、各々の値は $_
にセットされる。
配列値が(配列値を返す expression ではなく)実際の配列の場合は、
ループの中で変数を変更することで配列要素を変更することができる。例えば:
for (@ary) { s/foo/bar/; } foreach $elem (@elements) { $elem *= 2; } for ((10,9,8,7,6,5,4,3,2,1,'BOOM')) { print $_, "\n"; sleep(1); } for (1..15) { print "Merry Christmas\n"; } foreach $item (split(/:[\\\n:]*/, $ENV{'TERMCAP'})) { print "Item: $item\n"; }
ブロックはそれ自体(ラベルがついていてもいなくても)が
一回だけ実行されるループと同じである。そこで、ブロックから抜けたり、
ブロックを再実行したりするのにループコントロール文を使うことができる。
continue
ブロックもつけることができる。
このような構成は case
構造を記述するのに便利である。
foo: { if (/^abc/) { $abc = 1; last foo; } if (/^def/) { $def = 1; last foo; } if (/^xyz/) { $xyz = 1; last foo; } $nothing = 1; }
同様のことを記述する方法がいくつかあるので、
perl には正式な switch
文はない。上の例に付け加えると、
次のようにも書ける。
foo: { $abc = 1, last foo if /^abc/; $def = 1, last foo if /^def/; $xyz = 1, last foo if /^xyz/; $nothing = 1; }
または
foo: { /^abc/ && do { $abc = 1; last foo; }; /^def/ && do { $def = 1; last foo; }; /^xyz/ && do { $xyz = 1; last foo; }; $nothing = 1; }
または
foo: { /^abc/ && ($abc = 1, last foo); /^def/ && ($def = 1, last foo); /^xyz/ && ($xyz = 1, last foo); $nothing = 1; }
さらには
if (/^abc/) { $abc = 1; } elsif (/^def/) { $def = 1; } elsif (/^xyz/) { $xyz = 1; } else {$nothing = 1;}
実際にはこれらはすべて内部で switch 構造に最適化されるので、
perl は直接目的とする文へジャンプする。
だから一つの同じ単純なスカラー値を ==
や eq
や
上のようなパターンマッチングでテストするかぎりにおいては、
elsif
が 50 もあったりすると、
perl が不必要な文をたくさん実行するのではないか、という心配をする必要はない。
(もし、case ステートメントに最適化されているかどうかに興味があるなら、
-D1024
を用いて実行前にシンタックスツリーを表示させることができる。)
単文のみがその副作用を評価される expression である。 単文はすべてセミコロンで終わらなければならない。 これは C には似ているが、Pascal(そして awk)とは異なる点である。
単文は全て修飾子を一つ、終了を示すセミコロンの直前につけることができる。 以下のものが修飾子として使用可能である。
if EXPR unless EXPR while EXPR until EXPR
if
や unless
修飾子は見掛け通りの意味を持つ。
while
や until
修飾子もまた見掛け通りの意味をもつ
(条件は最初に評価される)が、
do-ブロック または do-サブルーチン コマンドに適用された場合は異なる。
この場合、条件文を評価する前にブロックを一回実行する。
これは次のようなループを書くことを可能にするためである。
do { $_ = <STDIN>; ... } until $_ eq ".\n";
(do
演算子の項を参照。また、この場合は、
ループコントロールコマンドは使えない。なぜなら、
修飾子はループラベルを持つことができないからである。あしからず。)See do.
**
**=
()
.
.=
eq
==
は数値の同値性)。
(もし、状況に応じて ==
が
文字列および数値の両方の同値性を表す awk に慣れているなら、注意せよ!)
ne
!=
は数値の非同値性)。
lt
gt
le
ge
cmp
<=>
=~
$_
に対して行うものがある。
=~
演算子を用いると、別の文字列に対してその演算が行われる。
右の引数は検索パターン・置換・変換(translation) であり、
左の引数はデフォルトの $_
の代わりに
検索・置換・変換の対象となる文字列である。返り値は演算の成否を返す。
(右引数が検索パターン・置換・変換 ではなくてある expression である場合は、
実行時に検索パターンとして解釈される。
その expression が評価される度にパターンがコンパイルされるので、
これはパターンを明示した検索に比べて非効率的である。)
この演算子は -
(単項マイナス演算子)、++
、--
を除く
他の演算よりも優先度が高い。
!~
=~
と同じである。
x
print '-' x 80; # ダッシュの列を出力する print '-' x80; # 正しくない、なぜなら x80 は識別子だから print "\t" x ($tab/8), ' ' x ($tab%8); # タブに変換 @ones = (1) x 80; # 80 個 1 が並んだ配列 @ones = (5) x @ones; # 全要素を 5 にする
x=
..
配列のコンテキストでは、
左の値から右の値まで(1 ずつ)増やした値を持つ配列を返す。
これは for (1..10)
ループや配列の一部を切り出す操作には便利である。
スカラーのコンテキストでは ..
は論理値を返す。
演算子はフリップフロップのように 2 通りの値をとる。
..
はそれぞれが自分だけの論理状態を持っていて、左引数が偽である限り、
偽の値を持つ。いったん左引数が真になると、右引数が真になるまで真である。
その後、範囲指定演算子は再び偽になる。
(次に範囲指定演算子が評価されるまで、偽にはならない。
真になったのと同じ評価を行った時に偽になることがありうるが、
それでも一度は真を返す。)演算子が偽の間は右引数は評価されず、
演算子が真の間は左引数は評価されない。
スカラー ..
演算子はもともと sed や awk にならって
行番号範囲指定をするためのものである。
優先度は ||
や &&
よりも少し低い。返り値は偽ならばヌル文字列、
真ならば(1 から始まる)連続した数字である。
この数字は範囲指定に出会う毎にリセットされる。
範囲の最後の数字には文字列 E0
がつけられるので、数値に影響はないが、
最後の点を除きたい場合に検索のきっかけとなる。
数字が 1 より大きくなるのを待つことで最初の点を除くことができる。
スカラーの ..
の引数のどちらかの値が静的な場合は、
引数は暗黙のうちに変数 $.
と比較される。
スカラー演算子としては:
if (101 .. 200) { print; } # 200 行出力する next line if (1 .. /^$/); # ヘッダー行をスキップ s/^/> / if (/^$/ .. eof()); # 本体を引用する
配列演算子としては:
for (101 .. 200) { print; } # $_ を 100 回出力する @foo = @foo[$[ .. $#foo]; # 高価なノーオペレーション @foo = @foo[$#foo-4 .. $#foo]; # 最後の 5 要素を取り出す
この演算子はファイル名かファイルハンドルを引数として一つとり、
そのファイルについて何かが真かどうかを見る。
引数を省略すると、$_
をテストする。
例外は -t
で、STDIN
をテストする。
真の場合は 1、偽の場合は ´´
か、
ファイルが存在しない場合は undefined value
を返す。
優先度は論理演算子、関係演算子よりも高いが、数学演算子よりは低い。
演算子の種類は、以下の通りである。
-r ファイルを実効 uid で読むことができる。 -w ファイルに実効 uid で書くことができる。 -x ファイルを実効 uid で実行することができる。 -o ファイルの所有者が実効 uid である。 -R ファイルを実 uid で読むことができる。 -W ファイルに実 uid で書くことができる。 -X ファイルを実 uid で実行することができる。 -O ファイルの所有者が実 uid である。 -e ファイルが存在する。 -z ファイルサイズが 0 である。 -s ファイルサイズが 0 でない(ファイルサイズを返す)。 -f ファイルはプレーンファイルである。 -d ファイルはディレクトリである。 -l ファイルはシンボリックリンクである。 -p ファイルは名前つきパイプ(FIFO)である。 -S ファイルはソケットである。 -b ファイルはブロック特殊ファイルである。 -c ファイルはキャラクター特殊ファイルである。 -u ファイルに setuid ビットがセットされている。 -g ファイルに setgid ビットがセットされている。 -k ファイルに sticky ビットがセットされている。 -t ファイルハンドルが tty にオープンされている。 -T ファイルはテキストファイルである。 -B ファイルはバイナリファイルである。(-T の逆) -M スクリプトの実行を開始した時点でのファイルの古さ(age)(単位は日) -A スクリプトの実行を開始した時点でのファイルのアクセス時間 -C スクリプトの実行を開始した時点でのファイルの inode 変更時間
演算子 -r
,-R
,-w
,-W
,-x
,-X
の判断は、
ファイルのモードとユーザの uid、gid のみによる。
実際に読み/書き/実行できない場合があるかもしれない。
また、スーパーユーザの場合は、
-r
,-R
,-w
,-W
は常に 1 を返し、
-x
,-X
については
ファイルモードにいずれかの実行許可がついていれば 1 を返す。
このため、スーパーユーザが実行するスクリプトにおいて
実際のファイルモードを得るためには、stat()
を行うか、
一時的に uid を他のものにセットする必要がある。
while (<>) { chop; next unless -f $_; # 特殊ファイルは無視する ... }
(注意)
-s/a/b/
としても、置換のマイナスをとるわけではない。
-exp($foo)
は期待通りに動く。しかし、
マイナスの後に 1 文字しかなければ、ファイルテストであると解釈される。
-T
および -B
は次のように動作する。
ファイルの最初のブロックについて、あまり出てこない文字 (奇妙なコントロールコード、メタキャラクター)があるかどうか検査する。 もしそれが多ければ(>10%)、バイナリファイルであり、 そうでなければテキストファイルである。
また、最初のブロックにヌルを含むファイルもバイナリとされる。
ファイルハンドルに対して -T
や -B
を使うと、
最初のブロックの替わりに現在の標準入力バッファが用いられる。
ヌルファイルや、ファイルハンドルをテストする時にファイルが EOF であると、
-T
も -B
も真を返す。
ファイルテストにおいて _
(下線)だけからなる
特殊なファイルハンドルを指定すると、
前回のファイルテスト(または stat()
)での stat
構造体が用いられ、
システムコールを行わない。
(-t
は除く。また、lstat()
や -l
は
実際のファイルではなくシンボリックリンクの情報を stat
構造体に残すことを
覚えておく必要がある。)
print "Can do.\n" if -r $a || -w _ || -x _; stat($filename); print "Readable\n" if -r _; print "Writable\n" if -w _; print "Executable\n" if -x _; print "Setuid\n" if -u _; print "Setgid\n" if -g _; print "Sticky\n" if -k _; print "Text\n" if -T _; print "Binary\n" if -B _;
perl になくて C にだけある演算子は以下の通り。
単項演算子 &
単項演算子 *
(型)
perl は C と同じく、演算子に対する引数が全て静的であり、 副作用もないと判断した時は expression の評価をコンパイル時に行う (特に、コンパイル時に変数置換を行わない文字列間の結合を発見した場合)。 バックスラッシュの解釈もコンパイル時に行われる。
'Now is the time for all' . "\n" . 'good men to come to.'
これは一つの文字列になってしまう。
++
演算子にはちょっとした細工をしている。
数字や、数値のコンテキストで使った変数をインクリメントすると、
通常のインクリメントを行う。
しかし、セットしてから文字列のコンテキストでしか使っておらず、
ヌルでない値を持っていて、
パターン /^[a-zA-Z]*[0-9]*$/
にマッチするような変数の場合、
文字列としてのインクリメントを文字列の範囲はそのまま、
キャリー付きで行う。
print ++($foo = '99'); # prints '100' print ++($foo = 'a0'); # prints 'a1' print ++($foo = 'Az'); # prints 'Ba' print ++($foo = 'zz'); # prints 'aaa'
--
演算子にはこのような細工はない。
(配列のコンテキストにおける)範囲演算子は、
最小値と最大値が文字列の場合は ++
演算子の細工を利用している。
アルファベット文字の全てを得るためには次のように記述できる。
@alphabet = ('A' .. 'Z');
また、16 進の値を得るためには、
$hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15];
そして、最初に 0 がついた日付を得るためには、
@z2 = ('01' .. '31'); print @z2[$mday];
と書ける。
(指定した最終値が ++
の細工が処理する順番になっていない場合は、
次の値が指定した最終値より長くなるまで繰り返される。)
||
や &&
は C のそれとは異なり、
0 や 1 を返す代わりに最後に評価した値を返す。このため、
ホームディレクトリを探すための移植性の高い方法は次のようになる。
$home = $ENV{'HOME'} || $ENV{'LOGDIR'} || (getpwuid($<))[7] || die "You're homeless!\n";
前章までに述べた文字や変数と同じく、 次章以降で述べる演算子は expression 中の"語"として機能する。 演算子の中にはリストを引数に取るものがある。 このリストはスカラーの引数や配列値が任意に結合されたものである。 配列値は、 リストのその位置に個々の要素を書いて 1 次元の配列値をたくさん生成したような形で リストに吸収される。
リストの要素はコンマで区切る必要がある。
演算子をリストすると、引数の前後に括弧がある場合ない場合共に、 その演算子を単項演算子または関数呼び出しとして使うことができる。
関数呼び出しとして使う場合は、 同じ行の次のトークンは左括弧でなくてはならない(間にスペースがあってもよい)。 このような関数は期待通りの最も高い優先度を持つ。
左括弧以外のトークンが続く場合は、単項演算子として扱われ、 リストを引数に取る演算子かそうでないかのみにより優先度が決まる。 リストを引数に取る場合は最も低い優先度になる。 他の全ての単項演算子は関係演算子よりは高いが数値演算子よりは低い優先度になる。 優先度の章を参照のこと。See Precedence.
do BLOCK
do BLOCK
は、BLOCK
で指示されるコマンド群の
最後のコマンドの値が返る。ループ修飾子で修飾された場合は、
ループ条件をテストする前に一回実行される。
(他の文ではループ修飾子は条件テストを最初に行う。)
do SUBROUTINE (LIST)
do SUBROUTINE
は、
sub
で宣言された SUBROUTINE
を実行し、
SUBROUTINE
で評価された最後の expression の値を返す。
その名前のサブルーチンがない場合は、致命的エラーとなる
(サブルーチンが存在するかどうか知るには、
defined
演算子を使用すれば良い。)。
LIST
の一部として配列を渡す場合、
各配列の前に配列の長さを渡してもいいだろう。
(後で出てくる subroutines
の章を参照。See Subroutines.)
do EXPR
との混乱を防ぐため、括弧は必要である。
SUBROUTINE
は一スカラー変数であってもよい。
この場合実行すべきサブルーチンの名前はその変数から取り出される。
別の書き方として(そして望ましい書き方として)、
名前の前に &
をつけてサブルーチンをコールしても良い。
例: &foo(@args)
引数を渡さないのであれば、括弧を使う必要はない。
括弧を省略した場合、サブルーチンには配列 @_
は渡されない。
&
形式は defined
および undef
に
サブルーチンを指示するのにも使える。
if (defined &$var) { &$var($parm); undef &$var; }
do EXPR
do EXPR
は、EXPR
をファイル名として、
そのファイルの内容を perl スクリプトとして実行する。
その主たる使用法は、
perl サブルーチンライブラリからサブルーチンをインクルードすることである。
do 'stat.pl';は、
eval `cat stat.pl`;
と全く同じである。
(より効率的で、より簡潔で、エラーメッセージでのファイル名は正しく、
カレントディレクトリになければ -I
で指定されたライブラリを
全て検索する点が異なる。See INC for @INC
.)
しかし、コールする毎に parse し直すのは同じなので、
ループの中で使用する際には -P
オプション
および #include
を使った方がよい(若干立ち上げ時間が増えるが)。
#include
の問題点は、cpp
は #
がコメントであることを
わかってくれないことである - コメントだけからなる行には ;#
を
使うことになる。
注意:
次の 2 文は同等ではない。
do $foo; # ファイルを評価する do $foo(); # サブルーチンを呼ぶ
ライブラリルーチンをインクルードするには require
オペレータがよい。
See require.
goto LABEL
LABEL
というラベル宣言を検索し、そこから実行を再開する。
現在は do {}
構造の中を除く
プログラムの本体内のラベルにしか goto
できない。
goto
はあまり効率的にはインプリメントされておらず、
sed-to-perl 変換を容易にしているだけである。私がいつ、
sed スクリプトのサポートは残したままこのセマンティクスを変更するかわからない。
使いたければ自らの責任で使うこと。全く使わないのが一番良い。
last LABEL
last
last
コマンドは C での break
(ループ中で使用される)
と似ている。現在実行中のループから直ちに抜け出す。
LABEL
を省略すると、最も奥のループを構成する囲みの最後にとぶ。
continue
がもしあっても、実行されない。
line: while (<STDIN>) { last line if /^$/; # ヘッダーが終わったら抜ける ... }
next LABEL
next
next
コマンドは C における continue
に似ていて、
ループの次の繰り返しを行う。
line: while (<STDIN>) { next line if /^#/; # コメントは捨てる ... }
注意:
もし continue
ブロックが上例にあれば、
無視される行であっても実行される。LABEL
を省略した場合、
next
は括弧で囲まれたループの最後にとぶ。
redo LABEL
redo
redo
コマンドは条件を評価することなくループブロックを再び実行する。
continue
ブロックがもしあっても、実行されない。
LABEL
を省略すると、最も内側の閉じたループを用いる。
このコマンドは通常、
入力された内容について自分自身に嘘をつくようなプログラムで用いる。
# 単純な Pascal コメント除去プログラム # (注意: 文字列中に {} がないと仮定している) line: while (<STDIN>) { while (s|({.*}.*){.*}|$1 |) {} s|{.*}| |; if (s|{.*| |) { $front = $_; while (<STDIN>) { if (/}/) { # コメントの終わり? s|^|$front{|; redo line; } } } print; }
return LIST
注意:
サブルーチンからは、最後に評価した expression の値で自動的に返る。
それがお勧めである -- return
を明示すると、若干遅くなる。
atan2(X,Y)
Y/X
の arctangent を -π から π までの範囲で返す。
cos(EXPR)
cos EXPR
EXPR
はラジアン。省略すると $_
を使う。
sin(EXPR)
sin EXPR
EXPR
(ラジアン) のサインを返す。
EXPR
を省略すると、$_
のサインを返す。
exp(EXPR)
exp EXPR
EXPR
乗を返す。
EXPR
を省略すると、exp($_
) を返す。
sqrt(EXPR)
sqrt EXPR
EXPR
のルート(2 乗根)を返す。
EXPR
を省略すると、$_
のルートを返す。
int(EXPR)
int EXPR
EXPR
を整数に変換した値を返す。
EXPR
を省略すると、$_
を使用する。
log(EXPR)
log EXPR
EXPR
の(基 e の)log を返す。
EXPR
を省略すると、$_
の log を返す。
rand(EXPR)
rand EXPR
rand
EXPR
の間のランダムな小数点の数値を返す
(EXPR
は正でなくてはならない)。
EXPR
を省略すると、0 と 1 の間の値を返す。srand()
も参照。
srand(EXPR)
srand EXPR
rand
演算子で用いる乱数の seed をセットする。
EXPR
を省略すると、srand(time)
を実行する。
time
gmtime()
や localtime()
に指定することができる。
gmtime(EXPR)
gmtime EXPR
time
関数が返す時間を Greenwich timezone として
要素数 9 の配列に変換する。典型的に以下のように使用される。
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
配列の全要素は数値であり、 struct tm
から直接得られたものである。
このため、$mon
は 0 から 11 まで、
$wday
は 0 から 6 までの値を取る。
EXPR
を省略すると、gmtime(time)
を実行する。
localtime(EXPR)
localtime EXPR
time
関数が返す形式の時間を local timezone として
要素数 9 の配列に変換する。典型的に以下のように用いる。
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
配列の要素はすべて数値で、struct tm
から直接得られるものである。
このため、$mon
は 0 から 11、$wday
は 0 から 6 の値を取る。
EXPR
を省略すると、localtime(time)
を実行する。
See time.
hex(EXPR)
hex EXPR
EXPR
を 16 進文字列であると見なして 10 進値を返す
(0
または 0x
で始まる文字列の変換については oct()
を参照。)。
EXPR
を省略すると、$_
を使用する。
oct(EXPR)
oct EXPR
EXPR
の値を 8 進文字列であると解釈してその 10 進値を返す。
(EXPR
が 0x
で始まる場合は代わりに 16 進文字列であると解釈する。)
次の例では、標準的な記述による 10、8、16 進を扱うことができる。
$val = oct($val) if $val =~ /^0/;
EXPR
を省略した場合、 $_
を使用する。
ord(EXPR)
ord EXPR
EXPR
の最初の文字の ascii value を数値で返す。
EXPR
を省略すると、$_
を使用する。
vec(EXPR,OFFSET,BITS)
BITS
は 2 の 1 乗から 32 乗まででなければならない。
vec()
が返すベクトルは論理演算子 |
、&
、^
を用いて
操作できる。両オペランドが文字列の場合はビットベクトル演算であると仮定する。
この解釈はプログラムに少なくとも一つの vec()
がないとなされない。
(古いプログラムを守るため)
ビットベクトルを文字列や 0 と 1 の配列に変換するには、 次のようにすればよい。
$bits = unpack("b*", $vector); @bits = split(//, unpack("b*", $vector));
正確なビット長がわかっているなら、
*
の代わりにそれを使うことができる。
pack(TEMPLATE,LIST)
pack
する。
構造体を含む文字列を返す。TEMPLATE
はひと続きの文字列で、
各文字は以下のように値のオーダーおよびタイプを表す。
A アスキー文字列(スペースが pad される)
a アスキー文字列(ヌルが pad される)
c signed char
C unsigned char
s signed short
S unsigned short
i signed integer
I unsigned integer
l signed long
L unsigned long
n short( "network" オーダー)
N long( "network" オーダー)
f 単精度浮動小数点(native format)
d 倍精度浮動小数点( 〃 )
p string へのポインタ
x null byte
X back up a byte(?)
@ 絶対位置までヌルで埋める
u uuencode された文字列
b ビット文字列
(vec()
のような、昇順のビットオーダー(ascending bit order))
B ビット文字列(降順のビットオーダー(descending bit order))
h 16進文字列(低 nybble が先に来る)
H 16進文字列(高 nybble が先に来る)
オプションとして数字を各文字の後につけて、繰り返し数を指定することができる。
a
、A
、b
、B
、h
、H
以外のタイプでは、
指定された数の値を LIST
から取る。
リピート値として *
を使うと残り全部を示す。
a
と A
では、値は一つで、指定された長さの一つの文字列として、
必要ならヌルやスペースを pad する。
(unpack
の際には、
A
は後に続くスペースやヌルを取り除くが、
a
の場合はそうではない。)
同様に、b
と B
は指定したビット数分の文字列を pack する。
h
と H
は指定した数の nybbles を pack する。
実数(単精度、倍精度)は native machine format のみである。
浮動小数点のフォーマットにはいろいろあり、
標準の network 表現がないので、交換することはできない。
このため、あるマシンで pack
された浮動小数点データは
他のマシンでは読むことができない --
たとえ両方共 IEEE の floating point arithmetic を使っていたとしても
(メモリ表現の endian-ness は IEEE のスペックにはないから)。
perl は内部の全数値計算に倍精度を用いているので、
double -> float -> double という変換をすると精度が悪くなる
(すなわち、unpack("f", pack("f", $foo))
は
普通 $foo
と一致しない)ことに注意。
$foo = pack("cccc",65,66,67,68); # foo は "ABCD" となる $foo = pack("c4",65,66,67,68); # 同じこと $foo = pack("ccxxcc",65,66,67,68); # foo は "AB\0\0CD" となる $foo = pack("s2",1,2); # リトル・エンディアンでの "\1\0\2\0" # ビッグ・エンディアンでの "\0\1\0\2" $foo = pack("a4","abcd","x","y","z"); # "abcd" $foo = pack("aaaa","abcd","x","y","z"); # "axyz" $foo = pack("a14","abcdefg"); # "abcdefg\0\0\0\0\0\0\0" $foo = pack("i9pl", gmtime); # 実際の構造体 tm (私のシステムでは) sub bintodec unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
unpack
関数でも、同じ template
を用いることができる。
unpack(TEMPLATE,EXPR)
unpack
は pack
の逆を行う:TEMPLATE
は pack
関数 と同じフォーマットである。
以下は substring
を行うサブルーチンの例である。
sub substr { local($what,$where,$howmuch) = @_; unpack("x$where a$howmuch", $what); }
そして、
sub ord { unpack("c",$_[0]); }
さらに、フィールドに %<数字>
という添え字をつけると、
アイテムそのものの代わりに、アイテムの<数字>ビットのチェックサムが得られる。
デフォルトは 16 ビットチェックサムである。
例えば、次の例では System V の sum
プログラムと同じ値が得られる。
while(<>) { $checksum += unpack("%16C*", $_); } $checksum %= 65536;
See pack.
chop(LIST)
chop(VARIABLE)
chop VARIABLE
chop
$_
を使う。
while (<>) { chop; # 最後の \n を取る @array = split(/:/); ...
左辺値であれば引数は何でもいい。
chop($cwd = `pwd`); chop($answer = <STDIN>);
リストを chop
した場合は、全リストを chop
し、
最後に chop
した文字を返す。
crypt(PLAINTEXT,SALT)
crypt()
と全く同じように encrypt
する。
パスワードファイル中のくだらないパスワードをチェックするのに便利である。
白い帽子を被った奴だけがこれをするべきだ。(?)
(Only the guys wearing white hats should do this.)
eval(EXPR)
eval EXPR
eval BLOCK
EXPR
を parse し、perl プログラムであるとみなして実行する。
現在の perl プログラムの環境で実行されるので、 変数、サブルーチン、フォーマット定義は後まで残る。 サブルーチンと同じく、評価した最後の expression の値が返る。
syntax error または runtime error があった場合、
または die
文が実行された場合、
eval
は undefined value を返し、
$@
にはエラーメッセージがセットされる。
エラーがなければ $@
はヌルであることが保証されている。
EXPR
が省略された場合は、$_
を評価する。
expression の最後にセミコロンがもしあれば、expression から除かれる。
See $at for $@
.
eval
は致命的エラーをトラップするので、
ある機能(例えば dbmopen
や symlink
)が
インプリメントされているかどうかを決定するのに便利である。
また、eval
は、perl の例外トラップ機構(exception trapping mechanism)
でもある。この例外を起こすためには die
演算子を用いる。
実行するコードが変化しないのであれば、
eval-BLOCK
形式を使うことにより、
毎回コンパイルし直す不利益を被ることなく
実行時のエラーをトラップすることができる。
エラーは、もしあれば、同様に $@ にセットされる。
シングルクォートされた文字列(EXPR)を eval
するのも同様の効果があるが、
eval-EXPR
はシンタックスエラーを実行時に $@ に返すのに対し、
eval-BLOCK
はシンタックスエラーをコンパイル時に返す点が異なる。
eval-EXPR
形式は、
その実行が最初に成功した時点で eval-BLOCK
形式に最適化される。
(文字列置換において e
修飾子を用いた場合、
置換側はシングルクォートされた文字列であると見なされるので、
同様の最適化がこの場合にもなされる。)
例:
# 0 除算を致命的エラーにしない eval { $answer = $a / $b; }; warn $@ if $@; # 最初に使った後、同じものに最適化される eval '$answer = $a / $b'; warn $@ if $@; # コンパイル時エラー eval { $answer = }; # 実行時エラー eval '$answer ='; # $@ をセットする
index(STR,SUBSTR,POSITION)
index(STR,SUBSTR)
STR
内で SUBSTR
が POSITION
文字目
またはそれ以降に最初に現れる位置を返す。
POSITION
を省略した場合は文字列の最初から検索する。
返り値のベースは 0 または $[
にセットされていればその値である。
SUBSTR
が見つからなければ、ベースから 1 を引いた値を返す。
通常 -1 である。
See $[.
length(EXPR)
length EXPR
EXPR
の値の文字列長を返す。
EXPR
を省略すると、$_
の長さを返す。
rindex(STR,SUBSTR,POSISION)
rindex(STR,SUBSTR)
index
と同じような動作をするが、
違いは STR
内に
最後に現れる SUBSTR
の位置を返すことである。
POSITION
を指定すると、
その位置またはそれより前で最後に現れる位置を返す。
See index.
substr(EXPR,OFFSET,LEN)
substr(EXPR,OFFSET)
EXPR
から文字列を取り出し返す。1 文字目はオフセット 0 であるが、
$[
にセットすることで変えることができる。OFFSET
が負の場合は、
文字列の終わりからその数分戻った所から始める。
LEN
を省略すると、文字列の残り全部を返す。
substr()
関数は左辺値として使うこともできるが、
この場合 EXPR
が 左辺値でなくてはならない。
LEN
よりも短いものを代入すると、その文字列は短くなり、
LEN
よりも長いものを代入するとそれに合わせて長くなる。
文字列の長さを変えない場合は sprintf
を用いて
パディングまたは切捨てをしなければならない。
See $[.
delete $ASSOC{KEY}
dbm
ファイルに bind された連想配列を削除すると、
dbm
ファイルのエントリを削除する。
以下の例では連想配列の全ての値を削除する。
foreach $key (keys %ARRAY) { delete $ARRAY{$key}; }
(が、reset
コマンドを使った方が速いだろう。
undef %ARRAY
はもっと速いだろう。)
each(ASSOC_ARRAY)
each ASSOC_ARRAY
従って、繰り返しができる。エントリーはランダムな順序で返ってくる。
全配列を読み終えると、 ヌル配列が返る(これは代入された場合は FALSE すなわち 0 になる)。 この後続けてコールすると繰り返しを再び始める。 繰り返し情報は全ての配列を読むことによってのみ初期化される。
繰り返しの途中では配列を変更してはいけない。
繰り返し情報は各連想配列に一つずつあり、
プログラム中の
全ての each()
, key()
, values()
関数コールで共有される。
次の例では printenv
のように環境をプリントアウトするが、順番が異なる。
while (($key,$value) = each %ENV) { print "$key=$value\n"; }
grep(EXPR,LIST)
LIST
の全要素について EXPR
を評価し
(各要素を $_
にセットしながら)、
expression が true であると評価された要素からなる配列を返す。
スカラーのコンテキストでは、expression が true となった回数を返す。
@foo = grep(!/^#/, @bar); # コメントを無視する
注意: $_
は配列値への参照となっているので、
配列要素を変更するのに用いることができる。これは便利である一方、
LIST
が名前のついた配列でない場合には、ちょっと変な結果を返すことがある。
join(EXPR,LIST)
join(EXPR,ARRAY)
LIST
または ARRAY
の個々の文字列を EXPR
の値で区切った
一つの文字列にする。
$_ = join(':',$login,$passwd,$uid,$gid,$gcos,$home,$shell);
See split.
keys(ASSOC_ARRAY)
keys ASSOC_ARRAY
values()
や each()
関数の出力と同じである
(連想配列が変更されていなければ)。
以下は環境を出力するまた別の方法である。
@keys = keys %ENV; @values = values %ENV; while ($#keys >= 0) { print pop(@keys), '=', pop(@values), "\n"; }
または、キーでソートしてみると、
foreach $key (sort(keys %ENV)) { print $key, '=', $ENV{$key}, "\n"; }
pop(ARRAY)
pop ARRAY
$tmp = $ARRAY[$#ARRAY--];
と同じ効果がある。配列に要素が一つもない場合は undefined value を返す。
See push.
push(ARRAY,LIST)
ARRAY
(@ は付けなくてよい)をスタックのように扱い、
LIST
の値を ARRAY
の最後に追加する。
ARRAY
の長さは LIST
の長さ分増える。
for $value (LIST) { $ARRAY[++$#ARRAY] = $value; }
と同じ効果を持つが、より効率がよい。
See pop.
reverse(LIST)
reverse LIST
LIST
の要素を逆順にした配列値を返す。
スカラーのコンテキストでは、
LIST
の最初の要素のバイト列を逆にした文字列を返す。
shift(ARRAY)
shift ARRAY
shift
ARRAY
を省略すると、
メインプログラムでは @ARGV
を shift
し、
サブルーチンでは @_ を shift
する。
(これは lexically(?) に決定される。)
unshift()
、push()
、pop()
も参照のこと。
shift()
と unshift()
は、
push()
と pop()
が配列の右について行うのと同じことを
配列の左について行う。
sort(SUBROUTINE LIST)
sort(LIST)
sort SUBROUTINE LIST
sort BLOCK LIST
sort LIST
LIST
をソートし、ソートされた配列を返す。
配列中の存在しない値は除かれる。
SUBROUTINE
または BLOCK
を省略すると、
標準的な文字列比較の順でソートする。
SUBROUTINE
を指定するときは、配列の要素の並べ替えかたに応じて、
0 より小、0、0 より大の整数値を返すサブルーチンの名前を指定する。
(このためのサブルーチンにおいては、
<=>
や cmp
といった演算子が大変便利である。)
SUBROUTINE
はスカラー変数の名前でもよい。
この場合その変数の値が使用するサブルーチンの名前を表す。
サブルーチン名の代わりに任意の BLOCK を指定して、 インラインのソートサブルーチンとすることができる。
効率を良くするため、通常のサブルーチンコールをとばしている。 このため、次の影響がある。
サブルーチンは再帰的であってはならない。
また、比較される 2 要素は @_
を通じてではなく、
$a
と $b
を通じてサブルーチンに渡される。(以下の例を参照。)
これらは参照渡しであるので、$a
と $b
を変更してはいけない。
例:
# 辞書順でソート @articles = sort @files; # 同様のものでソートルーチンを明示したもの @articles = sort {$a cmp $b;} @files; # 同様のもので逆順 @articles = sort {$b cmp $a;} @files; # 数値的に昇順にソート @articles = sort {$a <=> $b;} @files; # 数値的に降順にソート @articles = sort {$b <=> $a;} @files; # 明示的なサブルーチン名でソート sub byage { $age{$a} <=> $age{$b}; # 整数であると仮定している } @sortedclass = sort byage @class; sub reverse { $b cmp $a; } @harry = ('dog','cat','x','Cain','Abel'); @george = ('gone','chased','yz','Punished','Axed'); print sort @harry; # 出力は AbelCaincatdogx print sort reverse @harry; # 出力は xdogcatCainAbel print sort @george, 'to', @harry; # 出力は AbelAxedCainPunishedcatchaseddoggonetoxyz
splice(ARRAY,OFFSET,LENGTH,LIST)
splice(ARRAY,OFFSET,LENGTH)
splice(ARRAY,OFFSET)
ARRAY
から OFFSET
と LENGTH
で示された要素を除き、
LIST
があればそれと入れ替える。配列から除かれた要素を返す。
配列は必要に応じて大きくなったり小さくなったりする。
LENGTH
を省略すると、OFFSET
以降の要素が全て除かれる。
次の例は全てそれぞれ同等である。($[ == 0
であると仮定している。)
push(@a,$x,$y) splice(@a,$#a+1,0,$x,$y) pop(@a) splice(@a,-1) shift(@a) splice(@a,0,1) unshift(@a,$x,$y) splice(@a,0,0,$x,$y) $a[$x] = $y splice(@a,$x,1,$y);
次の例は、配列の長さが配列の前に渡されると仮定している。
sub aeq { # 2 つの配列値を比較する local(@a) = splice(@_,0,shift); local(@b) = splice(@_,0,shift); return 0 unless @a == @b; # 同じ長さ? while (@a) { return 0 if pop(@a) ne pop(@b); } return 1; } if (&aeq($len,@foo[1..$len],0+@bar,@bar)) { ... }
split(/PATTERN/,EXPR,LIMIT)
split(/PATTERN/,EXPR)
split(/PATTERN/)
split
split
し、その配列を返す。
(配列のコンテキストでない場合は、フィールドの数を返し、
split
の結果を @_
に格納する。
(配列のコンテキストでも、パターン delimiter に ??
を指定することで
@_ への代入を強制することができるが、返り値は配列値のままである。))
EXPR
を省略すると、文字列 $_
を split
する。
PATTERN
も省略すると、
whitespace (/[ \t\n]+/)
を split
する。
PATTERN
にマッチする文字は、
全てフィールドを分ける delimiter であると解釈される
(注意: delimiter は 1 字を超えてもよい)。
LIMIT
を指定すると、それを超えない数に split
する
(少ない場合もある)。LIMIT
を指定しない場合は、
余分なヌルフィールドが除かれる
(pop()
を使おうというユーザはこのことを覚えておいた方が良いのでは?)。
ヌル文字列にマッチするパターン(ヌルパターン //
と混同しないように。
//
はヌル文字列にマッチするパターン群の一つにすぎない)は
そのパターンがマッチする全ての点で EXPR
の値を文字に分割する。
print join(':', split(/ */, 'hi there'));
は h:i:t:h:e:r:e
を出力する。
LIMIT
パラメータは行の一部を split
するのに使用できる。
($login, $passwd, $remainder) = split(/:/, $_, 3);
(リストに代入する時に LIMIT
が省略されていると、
perl はリスト中の変数の数より 1 多い数を LIMIT
とする。
これは不必要な作業を無くすためである。
上のリストでは、LIMIT
はデフォルトで 4 であったはずである。
時間にクリティカルなアプリケーションでは
本当に必要なフィールド以上に分割しないようにするべきである。)
PATTERN
が括弧を含んでいる場合、
delimiter 中でマッチする文字列からさらに配列要素が作り出される。
split(/([,-])/,"1-10,20");
が作る配列の値は
(1,'-',10,',',20)
/PATTERN/
は
実行時に変化するパターンを指定する expression であってもよい。
(実行時コンパイルを 1 回だけ行うには、/$variable/o
を用いる。)
特殊な場合として、スペース (' '
) を指定すると、
何も指定しない場合と同じように white space で split
するが、
文字列の始めに whitespace があっても一番目にヌルフィールドを作らない。
すなわち、
split(' ')
は awk のデフォルトの動作をエミュレートするのに使える。
しかし、
split(/ /)
は文字列の最初のスペースの数だけヌルフィールドが得られる。
open(passwd, '/etc/passwd'); while (<passwd>) { ($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split(/:/); ... }
注意: 上の例で $shell
は改行文字を含む。chop()
を参照。
また、join
も参照のこと。
unshift(ARRAY,LIST)
shift
または push
の逆を行う。
LIST
を ARRAY
の前に付け、できた配列の要素数を返す。
unshift(ARGV, '-e') unless $ARGV[0] =~ /^-/;
values(ASSOC_ARRAY)
values ASSOC_ARRAY
keys()
や each()
関数が同じ配列に対して返すものと同じ順序である。
chmod(LIST)
chmod LIST
$cnt = chmod 0755, 'foo', 'bar'; chmod 0755, @executables;
chown(LIST)
chown LIST
uid
と gid
を最初の引数二つで(この順で)数値で指定する。
変更するのに成功したファイルの数を返す。
$cnt = chown $uid, $gid, 'foo', 'bar';
chown $uid, $gid, @filenames;
(例: passwd ファイルから数値でない uid
を検索する)
print "User: ";
$user = <STDIN>;
chop($user);
print "Files: "
$pattern = <STDIN>;
chop($pattern);
open(pass, '/etc/passwd')
|| die "Can't open passwd: $!\n";
while (<pass>) {
($login,$pass,$uid,$gid) = split(/:/);
$uid{$login} = $uid;
$gid{$login} = $gid;
}
@ary = <${pattern}>; # ファイル名を得る
if ($uid{$user} eq '') {
die "$user not in passwd file";
}
else {
chown $uid{$user}, $gid{$user}, @ary;
}
link(OLDFILE,NEWFILE)
lstat(FILEHANDLE)
lstat FILEHANDLE
lstat(EXPR)
lstat SCALARVARIABLE
stat()
関数と同じことをするが、
シンボリックリンクが指すファイルではなく、
シンボリックリンクそのものの stat
を返す。
シンボリックリンクをインプリメントしていないシステムでは、
stat
と同じである。
See stat.
mkdir(FILENAME,MODE)
FILENAME
で指定されるディレクトリを作成する。
permission
は MODE
(umask
で修飾される)で指定する。
成功すれば 1 を返し、失敗すれば 0 を返すと共に $!
をセットする(errno
)。
readlink(EXPR)
readlink EXPR
$!
をセットする(errno
)。
EXPR
を省略すると、$_
を用いる。
rename(OLDNAME,NEWNAME)
rmdir(FILENAME)
rmdir FILENAME
FILENAME
で指定されたディレクトリが空ならば消去する。
成功すれば 1、そうでなければ 0 を返し、$!
(errno
) をセットする。
FILENAME
を省略すると、$_
を用いる。
select(FILEHANDLE)
select
select
されているファイルハンドルを返す。
FILEHANDLE
を指定すれば出力のデフォルトファイルハンドルをセットする。
これには二つの効果がある。
write
または print
をファイルハンドルなしで用いると、
デフォルトのこの FILEHANDLE
が用いられる。
また、出力に関連づけられた変数への参照は、
この(select
で指定した)出力チャンネルを参照する。
例えば、
1 以上の出力チャンネルについてフォーマットの先頭行をセットしなければならない時は、
select(REPORT1); $^ = 'report1_top'; select(REPORT2); $^ = 'report2_top';
のようにすればよい。
FILEHANDLE
は
実際のファイルハンドルの名前を値として持つ expressionでもよい。
したがって、以下のように使える。
$oldfh = select(STDERR); $| = 1; select($oldfh);
select(RBITS,WBITS,EBITS,TIMEOUT)
bitmasks
を指定してシステムコール select
をコールする。
bitmasks
は 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);
または何かが ready になるまでブロックするには、
$nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
である。
bitmasks
はいずれも undef
にすることができる。
TIMEOUT
を指定する時は秒単位で、小数点も可能である。
注意:
インプリメントによっては$timeleft
を返す機能は利用できない場合がある。 その場合は常に指定した$timeout
と同じ値で$timeleft
が返る。
stat(FILEHANDLE)
stat FILEHANDLE
stat(EXPR)
stat SCALARVARIABLE
FILEHANDLE
でオープンされているか、
ファイルネームが EXPR
である
ファイルの statistics を表す 13 要素の配列を返す。
典型的には以下のように使用する。
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
stat
に特殊なファイルハンドルとしてアンダーラインを指定すると、
stat
を行わず、
最後の stat
または
ファイルテストの結果である stat
構造体の内容を返す。
if (-x $file && (($d) = stat(_)) && $d < 0) { print "$file is executable NFS file\n"; }(この例は NFS のデバイス番号が負になるようなマシンでのみ動作する。)
symlink(OLDFILE,NEWFILE)
OLDFILE
にシンボリックリンクされた NEWFILE
を作成する。
成功すれば 1、それ以外では 0 を返す。
シンボリックリンクをサポートしないシステムでは、実行時に致命的エラーとなる。
それをチェックするには、eval
を用いる。
$symlink_exists = (eval 'symlink("","");', $@ eq '');
truncate(FILEHANDLE,LENGTH)
truncate(EXPR,LENGTH)
FILEHANDLE
にオープンされたファイル
または EXPR
という名前のファイルを指定する長さに切り詰める。
システムに truncate
がインプリメントされていなければ致命的エラーとなる。
unlink(LIST)
unlink LIST
$cnt = unlink 'a', 'b', 'c'; unlink @goners; unlink <*.bak>;
注意: unlink
はスーパーユーザであって
かつ perl に -U
フラグを指定していないかぎりディレクトリは消去しない。
これらの条件にあてはまっている場合でも、
ディレクトリを unlink
することは
ファイルシステムにダメージを与えることに注意せよ。
かわりに rmdir
を使うこと。
utime(LIST)
utime LIST
touch
コマンドの例:
#!/usr/bin/perl $now = time; utime $now, $now, @ARGV;
closedir(DIRHANDLE)
closedir DIRHANDLE
opendir()
で open
されたディレクトリを close
する。
opendir(DIRHANDLE,EXPR)
EXPR
という名前のディレクトリを open
し、
readdir()
、telldir()
、seekdir()
、rewinddir()
、closedir()
を可能にする。
成功すれば true を返す。DIRHANDLEs
には FILEHANDLEs
とは別の名前空間がある。
readdir(DIRHANDLE)
readdir DIRHANDLE
opendir()
でオープンしたディレクトリの次のエントリを返す。
配列のコンテキストで用いると、ディレクトリの残りのエントリを全て返す。
エントリが残っていない場合は、スカラーのコンテキストでは undefined value、
配列のコンテキストではヌルリストを返す。
rewinddir(DIRHANDLE)
rewinddir DIRHANDLE
readdir()
で用いる、
DIRHANDLE
のカレント位置をディレクトリの最初にセットする。
seekdir(DIRHANDLE,POS)
readdir()
で用いる DIRHANDLE
のカレント位置をセットする。
POS
はtelldir()
が返す値でなくてはならない。
directory compaction については
対応するシステムライブラリ関数と同様の注意が必要である。
telldir(DIRHANDLE)
telldir DIRHANDLE
DIRHANDLE
に対する readdir()
の現在の位置を返す。
ディレクトリのある位置にアクセスするために
この値を seekdir()
に指定することができる。
directory compaction については
対応するシステムライブラリルーチンと同じ注意が必要である。
以下の項目の説明における FILEHANDLE
は、
open
でオープンされたファイルハンドルか、
ファイルハンドルの名前を値に持つスカラー変数である。
binmode(FILEHANDLE)
binmode FILEHANDLE
CR LF
が LF
に、
出力の際に LF
が CR LF
に変換される。
Unix の下では何の効果もない。
FILEHANDLE
がexpression の場合は、
その値がファイルハンドルの名前として解釈される。
close(FILEHANDLE)
close FILEHANDLE
同じ FILEHANDLE
を用いてすぐにまた open
する場合は、
close
する必要は無いが(open
が close
する)、
入力ファイルに対して明示的に close
を行うと
ラインカウンタ($.
)がリセットされる
(open
の行う close
ではそうならない)。
また、パイプを close
する時には
そのパイプを用いて実行されているプロセスが終わるのを待つ
(あとでパイプの出力を見ることができるように)。
パイプを明示的に close
するとコマンドの status が $?
に入る。
open(OUTPUT, '|sort >foo'); # pipe to sort ... # print stuff to output close OUTPUT; # wait for sort to finish open(INPUT, 'foo'); # get sort's results
FILEHANDLE
はファイルハンドルの名前を値として持つ expression でもいい。
dbmclose(ASSOC_ARRAY)
dbmclose ASSOC_ARRAY
dbm
ファイルと連想配列の bind を終了する。
連想配列に残っている値は意味がない。
この関数は ndbm
がある場合にのみ便利である。
dbmopen(ASSOC,DBNAME,MODE)
dbm
または ndbm
ファイルと連想配列を bind
する。
ASSOC
は連想配列の名前である(似てはいるけれど、
普通の open
と違い、最初の引数はファイルハンドルではない)。
DBNAME
はデータベースの名前から
.dir
または .pag
の拡張子をとったものである。
データベースが存在しなければ、
MODE
で指定される protection で作成される。
古い dbm
関数しかサポートしていないシステムの場合は、
プログラム中で dbmopen
は一回しか実行することができない。
dbm
も ndbm
もないシステムで dbmopen
をコールすると
致命的エラーとなる。
dbmopen
の前の連想配列の値は失われる。
dbm
ファイルの値の一部はメモリにキャッシュされる。
これはデフォルトでは 64 個であるが、
dbmopen
に先立って連想配列にダミーの値を代入することで増やすことができる。
必要なら、reset
コマンドでキャッシュをフラッシュすることができる。
dbm
ファイルに書き込み許可がない場合、
連想配列の値を読むことはできても、代入はできない。
書き込みができるかどうかテストするのなら、ファイルテストを使うか、
eval
中でダミーの配列をセットしてみて、
エラーが起こるかどうかで判断することができる。
大きな dbm
ファイルの場合、
keys()
や values()
といった関数は巨大な配列を返すことがある。
each()
を用いて
大きな dbm
ファイルについて繰り返しを行いたい場合は、次の例を参照。
# ヒストリーファイルのオフセットを出力 dbmopen(HIST,'/usr/lib/news/history',0666); while (($key,$val) = each %HIST) { print $key, ' = ', unpack('L',$val), "\n"; } dbmclose(HIST);
eof(FILEHANDLE)
eof()
eof
FILEHANDLE
に対する次の読み込みが end of file を返すか、
FILEHANDLE
がopen
されていない場合、1 を返す。
FILEHANDLE
は ファイルハンドルの名前を値に持つ expression でもよい。
(注意: この関数は実際には 1 文字読み込んでそれを ungetc
するので、
インタラクティブなコンテキストではあまり有用ではない。)
引数なしの eof
は最後に読み込んだファイルの eof status を返す。
空の括弧 ()
は、コマンドラインで指定されたファイルから作られる
擬似ファイルを指定するのに使われる。
即ち、eof()
は while (<>)
の中で
最後のファイルの終わりを検出するために使う時のみ意味がある。
while (<>)
ループの全てのファイルの終わり検出のためには、
eof(ARGV)
か 括弧のない eof
を使うべきである。
# 最後のファイルの最後の 1 行前にダッシュを入れる while (<>) { if (eof()) { print "--------------\n"; } print; } # 各入力ファイルごとに行番号をリセットする while (<>) { print "$.\t$_"; if (eof) { # eof() ではない。 close(ARGV); } }
fcntl(FILEHANDLE,FUNCTION,SCALAR)
ioctl(2)
関数をインプリメントする。正しく関数を定義するにはおそらく
require "fcntl.ph"; # たぶん /usr/local/lib/perl/fcntl.ph
を最初に行う必要があるだろう。
fcntl.ph
がなかったり正しく定義されていなければ、
<sys/fcntl.h>
などに基づいて自分で定義する必要がある。
(perl キットにはこの作業を助けるための
h2ph
という perl スクリプトがある。)
引数の処理や返り値は ioctl
と全く同じである。
注意: fcntl(2)
をインプリメントしていないマシンで使用すると
致命的エラーとなる。
fileno(FILEHANDLE)
fileno FILEHANDLE
select()
の bitmap
を構築するのに便利である。
FILEHANDLE
が expression の場合は、
その値がファイルハンドルの名前であると解釈される。
flock(FILEHANDLE,OPERATION)
FILEHANDLE
について flock(2)
をコールする。
OPERATION
の定義については flock(2)
のマニュアルを参照のこと。
成功すると true、失敗すると false を返す。
flock(2)
をインプリメントしていないマシンで使用すると
致命的エラーとなる。以下は BSD システム用 mailbox appender である。
$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'}") || die "Can't open mailbox: $!"; do lock(); print MBOX $msg,"\n\n"; do unlock();
getc(FILEHANDLE)
getc FILEHANDLE
getc
FILEHANDLE
に結び付いている入力ファイルの次の character を返す。
EOF
の場合はヌル文字列を返す。
FILEHANDLE
を省略すると、STDIN
から読む。
ioctl(FILEHANDLE,FUNCTION,SCALAR)
ioctl(2)
関数をインプリメントする。正しく関数を定義するにはおそらく
require "ioctl.ph"; # probably /usr/local/lib/perl/ioctl.ph
を最初に行う必要があるだろう。
ioctl.ph
がなかったり正しく定義されていなければ、
<sys/ioctl.h>
などに基づいて自分で定義する必要がある。
(perl キットには、
この作業を助けるための h2ph
という perl スクリプトがある。)
SCALAR
は FUNCTION
により、
参照かつまたは代入される -- SCALAR
の文字列値へのポインタが
実際の ioctl
コールの三番目の引数として渡される。
(SCALAR
が文字列値でなくて数値の場合は、
文字列値へのポインタではなくその値が渡される。
これを常に保証するには、SCALAR
にあらかじめ 0 を足せば良い。)
ioctl()
で使用される構造体の値を操作するには、
pack()
や unpack()
関数が便利である。
次の例では、erase character を DEL
にセットする。
do 'ioctl.ph'; $sgttyb_t = "ccccs"; # char 4 つと 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 undefined value
0 string 0 but true
それ以外 その値
つまり、perl は成功すれば真、失敗すれば偽を返すが、 OS が返す実際の値を簡単に得ることもできる。
($retval = ioctl(...)) || ($retval = -1); printf "System returned %d\n", $retval;
open(FILEHANDLE,EXPR)
open(FILEHANDLE)
open FILEHANDLE
EXPR
で指定されるファイルを open
し、
FILEHANDLE
と結び付ける。
FILEHANDLE
が expression の場合は、
その値が実際のファイルハンドルの名前として用いられる。
EXPR
を省略した場合、
FILEHANDLE
と同名のスカラー変数がファイル名を持つ。
<
で始まるか何も付いていない場合は
ファイルは入力用にopen
される。
>
で始まる場合は出力用に open
される。
>>
で始まる場合は 追加用に open
される。
>
や <
の前に +
を付けると
ファイルに対し read
および write
両方の許可を得ることができる。
|
で始まる場合はコマンドであると解釈され、
出力がそのコマンドにパイプされる。
|
で終わる場合もコマンドであると解釈され、
そのコマンドから入力がパイプされる。
(入力・出力両方をパイプするコマンドは必要ないであろう。)
-
は STDIN
を open
し、
>-
は STDOUT
を open
する。
成功すれば non-zero を返し、そうでない場合は undefined を返す。
open
がパイプを含む場合、返り値はサブプロセスの pid
になる。
$article = 100; open article || die "Can't find article $article: $!\n"; while (<article>) { ... open(LOG, '>>/usr/spool/news/twitlog'); # (log は予約語である) open(article, "caesar <$article |"); # 記事を decrypt する open(extract, "|sort >/tmp/Tmp$$"); # $$ は現在のプロセス # # 引数のファイルリストについて # それがインクルードするファイルも含めて処理する foreach $file (@ARGV) { do process($file, 'fh00'); # no pun intended } sub process { local($filename, $input) = @_; $input++; # これは文字列のインクリメントである unless (open($input, $filename)) { print STDERR "Can't open $filename: $!\n"; return; } while (<$input>) { # 間接指定に注意 if (/^#include "(.*)"/) { do process($1, $input); next; } ... # whatever } }
Bourne shell
の慣習で、EXPR
を >&
で始めても良い。
この場合、残りの文字列は ファイルハンドル
(または数値ならば ファイルディスクリプタ)と解釈され、
dup
され、open
される。
&
は >
, >>
, <
,
+>
, +>>
, +<
の後で用いて良い。
指定するモードは元のファイルハンドルと同じでなければならない。
以下のスクリプトは 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";
コマンド -
を用いてパイプを open
する場合、
すなわち |-
または-|
の場合、
暗黙の内に fork
がなされ、
open
の返り値は親プロセスでは子プロセスの pid
、
子プロセスでは 0 になる。
(open
が成功したかどうかは defined($pid)
で確かめる。)
ファイルハンドルの挙動は親プロセスでは通常と同じであるが、
そのファイルハンドルへの i/o は
子プロセスの STDOUT
/STDIN
にパイプされる。
子プロセスではファイルハンドルは open
されていない --
i/o は新たな STDOUT
から/STDIN
に なされる。
良く使われるのは、例えば setuid
で走らせているときなど、
パイプコマンドの実行状態をコントロールしたい時や、
シェルコマンドにメタキャラクターがあるかどうかをチェックしたくない時である。
次の 2 つのペアはそれぞれある程度(more or less)同等である。
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
すると
親プロセスは子プロセスが終了するのを待ち、status 値 $?
が返り値となる。
注意:
fork
を行う操作においては、
フラッシュされていないバッファは両方のプロセスにおいてフラッシュされずに残る。
つまり、二重に出力されるのを避けるには、
$|
をセットしなければならない。See $vline for $|
.
open
に渡されるファイル名は最初や最後のスペースを取り除かれる。
名前におかしな文字が含まれるファイルを open
するには、
次のようにして前後のスペースが取り除かれないようにしなければならない。
$file =~ s#^(\s)#./$1#; open(FOO, "< $file\0");
pipe(READHANDLE,WRITEHANDLE)
WRITEHANDLE
をコマンド毎にフラッシュするために、
$|
をセットする必要があるかもしれない。
See $vline for $|
.
[perl 3.0 パッチレベル 9 以上が必要。]
print(FILEHANDLE LIST)
print(LIST)
print FILEHANDLE LIST
print LIST
print
FILEHANDLE
は
ファイルハンドルの名前を値として持つスカラー変数名でもよい。
こうすると、1 レベルの間接的な出力ができる。
(注意: FILEHANDLE
が変数で、次のトークンが文の終わりの場合は
それが演算子と誤解釈される可能性があるので、間に +
を入れるか、
引数に括弧をつけるかしなければならない。)
FILEHANDLE
を省略すると、
デフォルトでは標準出力(または最後に select
された出力チャンネル --
select()
参照 See select.)に出力する。
LIST
も省略すると、$_
を STDOUT
に出力する。
デフォルトの出力チャンネルを STDOUT
以外のものにするには、
select
演算子を使用する。
注意:
print
は LIST
を引数に取るので、
LIST
の要素は全て配列のコンテキストで評価され、
またサブルーチンをコールすると
その 1 つ以上の expression は配列のコンテキストで評価される。?
また、キーワード print
の後に左括弧はつけないように注意する必要がある
(print
への引数を区切る --
+
を間に入れるか全引数を括弧で囲む --
ために対応した右括弧をつけたい場合を除いて)。
printf(FILEHANDLE LIST)
printf(LIST)
printf FILEHANDLE LIST
printf LIST
print FILEHANDLE sprintf(LIST)
と同等である。
read(FILEHANDLE,SCALAR,LENGTH,OFFSET)
read(FILEHANDLE,SCALAR,LENGTH)
FILEHANDLE
から、
LENGTH
バイトのデータを読んで SCALAR
に格納する。
実際に読み込んだバイト数、またはエラーがあれば undef
を返す。
SCALAR
は実際に読んだバイト数に合わせてサイズが変わる。
OFFSET
を指定すると、
読んだデータを文字列の先頭ではなく他の場所に格納する。
これは実際には、
stdio
の fread
コールを用いてインプリメントしている。
本当の read
システムコールを使いたければ、sysread
を参照せよ。See sysread.
seek(FILEHANDLE,POSITION,WHENCE)
FILEHANDLE
のファイルポインタを任意の位置に移動する。
stdio
のfseek()
と同じである。
FILEHANDLE
はファイルハンドルの名前を値として持つ expression でもよい。
成功すれば 1、そうでなければ 0 である。
sprintf(FORMAT,LIST)
printf
の習慣でフォーマットされた文字列を返す。*
はサポートしていない。
sysread(FILEHANDLE,SCALAR,LENGTH,OFFSET)
sysread(FILEHANDLE,SCALAR,LENGTH)
read(2)
を用いて、
指定したファイルハンドルから
変数 SCALAR
に LENGTH
バイトのデータを読み込む。
これは stdio
を経由しないので、
他の種類の読み込みと一緒に使うと混乱することがある。
実際に読んだバイト数を返す。エラーがあった場合は undef を返す。
読み込んだデータを文字列の先頭からではなく別の位置に格納するために、
OFFSET
を指定してもよい。
syswrite(FILEHANDLE,SCALAR,LENGTH,OFFSET)
syswrite(FILEHANDLE,SCALAR,LENGTH)
write(2)
を用いて、
指定したファイルハンドルに
変数 SCALAR
から LENGTH
バイトのデータを書き込む。
これは stdio
を経由しないので、
print
と一緒に使うと混乱することがある。
実際に書き込んだバイト数を返す。エラーがあった場合は undef を返す。
書き込むデータを文字列の先頭からではなく別の位置から取り出すために、
OFFSET
を指定してもよい。
tell(FILEHANDLE)
tell FILEHANDLE
tell
FILEHANDLE
の現在のファイル位置を返す。
FILEHANDLE
は
実際のファイルハンドルの名前を値として持つ expression であってもよい。
FILEHANDLE
を省略すると、最後に読んだファイルを仮定する。
write(FILEHANDLE)
write(EXPR)
write
select
参照)のフォーマットは
フォーマットの名前を $~
に指定することで明示できる。
See $tilde for $~
.
整形操作は自動的に行われる。 現在のページにフォーマットしたレコードに対して充分な余裕がない場合は 改頁を出力して次のページに移り、 新しいページのヘッダーをフォーマットするには 特殊なページ先頭フォーマットが使われ、 こうしてレコードが出力される。
デフォルトではページ先頭フォーマットは
ファイルハンドル名に "_TOP
" をつけたものであるが、
ファイルハンドルが select
されている時に $^
に代入することで
好みのフォーマットに動的に変更することができる。
See $hat for $^
.
現在のページに残っている行数は変数 $-
に入っており、
これを 0 にセットして強制的に新しいページに入ることができる。
FILEHANDLE
を指定しない場合は、
出力は現在のデフォルト出力チャンネルになされる。
これは最初は STDOUT
で、select
を用いて変更可能である。
FILEHANDLE
が expression の場合は、実行時に expression が評価され、
その結果の文字列が FILEHANDLE
の名前として用いられる。
format
についての詳細は、Format
の章を参照のこと。
See Formats.
注意: write
は read
の反対ではない。
m/パターン/ と同じ。次項を参照。
m/PATTERN/gio
/PATTERN/gio
(1)
または false (´´)
を返す。
=~
や !~
で文字列を指定しない場合は $_
文字列を検索する。
(=~
で指定される文字列は左辺値である必要はない --
expression 評価の結果でも良いが、 =~
の方が優先度が高いことに注意。)
Regular Expression
の章も参照のこと。
See Regular Expression.
/
が delimiter であるなら、最初の m
は省略可能である。
m
を使うと、
アルファベット・数字でない任意の文字のペアを delimiter として使える。
これは Unix のパス名(/
を含む)のマッチングをするのに便利である。
二つ目のdelimiter の後にオプション i
をつけると、
case insensitive でマッチングを行う。
PATTERN
はスカラー変数を含んでいても良いが、
パターン検索を行う毎に置き換えが行われる(そしてパターンが再コンパイルされる)。
(注意:$)
と $|
は文字列の終わりのチェックに使われるであろうから、
置き換えは行われない。)
パターンを最初の一回だけコンパイルさせたい時は、
最後のオプションに o
を指定する。
こうすると実行時の再コンパイルを避けることができるので、
変数で置き換えている値がスクリプト実行中に変わらないのであれば、便利である。
PATTERN
がヌル文字列に評価された場合、
直前に成功した正規表現が代わりに用いられる。
配列値が必要な文脈で使うと、パターンマッチはパターンを括弧でくくったもの、
すなわち ($1, $2, $3 ...)
にマッチする subexpression からなる
配列を返す。実際には $1
、$2
などをセットせず、
この場合だと、$+
、$`
、$&
、$'
もセットしない。
マッチングが失敗した場合、ヌル配列が返る。
マッチングが成功した場合、括弧が一つもなければ、配列値 (1)
が返る。
open(tty, '/dev/tty'); <tty> =~ /^y/i && do foo(); # y と答えたら do foo if (/Version: *([0-9.]*)/) { $version = $1; } next if m#^/usr/spool/uucp#; # poor man's grep $arg = shift; while (<>) { print if /$arg/o; # 1 回だけコンパイルする } if (($F1, $F2, $Etc) = ($foo =~ /^(\S+)\s+(\S+)\s*(.*)/))
最後の例は、$foo
を二つの word と残りに分け、
これら三つのフィールドを $F1
, $F2
, $Etc
に代入する。
どの変数が変更されても、すなわち、パターンがマッチすれば、条件は真である。
修飾子 "g"
はグローバルパターンマッチを指定する -- すなわち、
文字列中で可能なかぎりマッチを行なう。
コンテキストによりどのように振舞うか。
配列のコンテキストでは、
正規表現中のすべての括弧とマッチする substring からなるリストを返す。
括弧が一つもない場合、パターン全体の回りに括弧があるかのように扱い、
マッチした全文字列のリストを返す。
スカラーのコンテキストでは、文字列全体について繰り返しを行い、
マッチする度に TRUE を返し、ついにマッチしなくなった時点で FALSE を返す。
(言い替えれば、前にどこまでマッチを行なったかを覚えておき、
その位置から検索を再開する。)
最後のマッチを行なってから文字列を変更していないということを仮定している。
マッチの間で文字列を変更すると未定義の動作を行なう可能性がある。
(実は、substr()
を使って全文字列の長さを変えないで
文字列をその場で(in-place)変更する場合にはうまくいく。しかし、一般的には、
そのような変更を行なう場合は s//g
を使うべきである。)
例:
# array context ($one,$five,$fifteen) = (`uptime` =~ /(\d+\.\d+)/g); # scalar context $/ = 1; $* = 1; while ($paragraph = <>) { while ($paragraph =~ /[a-z]['")]*[.!?]+['")]*\s/g) { $sentences++; } } print "$sentences\n";
See Regular Expression.
?PATTERN?
reset
から reset
までで 1 回しかマッチしないことを除いて、
/パターン/ 検索と同じである。例えば、幾つかあるファイルの各々について、
あるものが最初に現れるのを調べるのに便利である。
現在のパッケージにローカルな ??
パターンのみリセットされる。
See reset.
s/PATTERN/REPLACEMENT/gieo
PATTERN
を持つ文字列を検索し、
見つかれば、REPLACEMENT
テキストと置き換え、置換を行った数を返す。
見つからなければ false (つまり 0)を返す。
オプションとして g
をつけると、
見つかった全てのパターンについて置換を行う。
e
も同様にオプションで、
REPLACEMENT
は ""
で括られた文字列ではなく、
expression として評価される。
スラッシュの代わりに アルファベット・数字でない任意の文字を delimiter としてよい。
REPLACEMENT
について interpret しない
(e
はこれに優先する)。
REPLACEMENT
は実行すべきコマンド名と見なされ、
その出力が実際の置換文字列として用いられる。
=~
演算子 や !~
演算子を通して文字列を指定しなければ、
$_
について検索し、置換する。
(=~
を用いて指定する文字列はスカラー変数、配列の要素、
またはこれら 2 つへの代入、即ち、左辺値でなければならない。)
PATTERN
が $
を含み、
"文字列最後"ではなくて"変数"に見える場合は、
実行時にその変数が PATTERN
に書き込まれる。
パターンのコンパイルを最初の一回だけにし、変数の書き換えを行いたい時は、
o
を最後につける。PATTERN
がヌル文字列に評価された場合、
直前に成功した正規表現が代わりに用いられる。正規表現の項を参照。
s/\bgreen\b/mauve/g; # wintergreen は変更しない $path =~ s|/usr/bin|/usr/local/bin|; s/Login: $foo/Login: $bar/; # 実行時に決まるパターン ($foo = $bar) =~ s/bar/foo/; $_ = 'abc123xyz'; s/\d+/$&*2/e; # 'abc246xyz' を出力 s/\d+/sprintf("%5d",$&)/e; # 'abc 246xyz' を出力 s/\w/$& x 2/eg; # 'aabbcc 224466xxyyzz' を出力 s/([^ ]*) *([^ ]*)/$2 $1/; # 最初の 2 フィールドを入れ替え
注意:
最後の例で \
の代わりに $
を使用していることに注意。
正規表現の項を参照。See Regular Expression.
study(SCALAR)
study SCALAR
study
SCALAR
(指定しなければ $_
)について、
それが次に変更される前に多くのパターンマッチをあらかじめ行う。
検索を行うパターンの性質や数、検索される文字列中の文字の頻度分布により
時間が節約されるかもしれないし、されないかもしれない。
多分これを使用するのとしないのと、
どちらが早く実行できるかを比較してみたいであろう。
数多くの短い定数文字列(より複雑なパターン中の定数部を含む)について
検索を行うループにおいて最も効果があるだろう。
同時に 1 つしか study
できない。
別のスカラーを study
すると、
最初に study
した方は unstudied
になってしまう。
(study
の動作は次のようになる:
検索対象の文字列の全文字の linked list を作り、これにより、例えば、
全ての k
という文字がどこにあるかがわかる。
C プログラムおよび英文から得た統計的な頻度テーブルに基づいて、
各検索文字列から最も稀な文字を選ぶ。
この"最も稀な"文字を含む位置のみを調べるのである。)
例えば、次のループは、あるパターンを含む行の前に、 インデックスを含むエントリを出力するものである。
while (<>) { study; print ".IX foo\n" if /\bfoo\b/; print ".IX bar\n" if /\bbar\b/; print ".IX blurfl\n" if /\bblurfl\b/; ... print; }
/\bfoo\b/
を検索する時は、
$_
中の f
の位置のみを調べる。
なぜなら、f
は o
よりも稀だからである。
一般的に、特殊な場合を除いてこれは効果がある。
唯一の問題は、これにより最初に linked list を作るのにかかった以上に
時間を節約できるかどうかである。
注意:
実行時まで決定できない文字列を検索する場合は、
ループを全部文字列としてそれを eval
することで
何回も全パターンをコンパイルし直すのを防ぐことができる。
これと合わせて、$/
を全ファイルが 1 レコードになるように undef すると、
大変速く、専用のプログラム fgrep
よりも速いことが多い。
以下の例では ファイル群(@files
) から単語群(@words
) を検索し、
マッチするファイルの名前を出力する。
$search = 'while (<>) { study;'; foreach $word (@words) { $search .= "++\$seen{\$ARGV} if /\b$word\b/;\n"; } $search .= "}"; @ARGV = @files; undef $/; eval $search; # これは大変(this screams) $/ = "\n"; # 通常の delimiter に戻す foreach $file (sort keys(%seen)) { print $file, "\n"; }
tr/SEARCHLIST/REPLACEMENTLIST/cds
y/SEARCHLIST/REPLACEMENTLIST/cds
SEARCHLIST
に指定した全ての文字を、
REPLACEMENTLIST
にしたがって変換する。
置換もしくは削除した文字数を返す。
=~
や !~
を使って文字列を指定しなかった場合は、
$_
文字列が変換される。
(=~
を使って指定する文字列はスカラー変数、配列の 1 要素、
またはこれらへの代入でなくてはならない。即ち、左辺値。)
sed 信者のために、y
も tr
の別名としてある。
c
を指定すると、
SEARCHLIST
文字セットの補集合が使われる。
d
を指定すると、SEARCHLIST
によって指定される文字で、
REPLACEMENTLIST
内にないものが全て削除される。
(注意: これは tr
プログラムの挙動に比べてより柔軟な処理である。
tr
プログラムには、
SEARCHLIST
に含まれる文字を全て削除するものがある)
s
を指定すると、
変換されて同じ文字になった文字列を 1 文字に縮める。
修飾子 d
を用いると、
REPLACEMENTLIST
は常に指定したそのものとして解釈される。
それ以外の場合で、
REPLACEMENTLIST
が SEARCHLIST
よりも短い場合は、
同じ長さになるまで最後の文字が繰り返される。
REPLACEMENTLIST
がヌルの場合は、SEACHLIST
がコピーされる。
この後者は、あるクラスに含まれる文字をカウントしたり、 あるクラスの文字の連続を縮めたりするのに便利である。
$ARGV[1] =~ y/A-Z/a-z/; # 小文字に統一する $cnt = tr/*/*/; # $_ 内の * を数える $cnt = tr/0-9//; # $_ 内の数字を数える tr/a-zA-Z//s; # bookkeeper -> bokeper ($HOST = $host) =~ tr/a-z/A-Z/; y/a-zA-Z/ /cs; # アルファベット以外を 1 文字のスペースに置換 tr/\200-\377/\0-\177/; # 8 ビット目を消す
y/SEARCHLIST/REPLACEMENT/
alarm(SECONDS)
alarm SECONDS
SIGALRM
をプロセスに伝える。
つまり、
alarm(15)
はそれから 14 秒以上経ったある時点で SIGALRM
を起こす。
同時には一つのタイマーしかカウントできない。 コールする度に前のタイマーを使えなくするし、 また引数として 0 を与えると 新しいタイマーを開始せずに前のタイマーをキャンセルする。
返り値は前のタイマーに残っていた時間である。
chdir(EXPR)
chdir EXPR
EXPR
省略時はホームディレクトリ。
chroot(FILENAME)
chroot FILENAME
FILENAME
が省略された場合、$_
に chroot
する。
die(LIST)
die LIST
eval
の外では、LIST
の値を STDERR
に出力し、
現在の $!
(errno
) で exit
する。
もし $!
が 0 なら、
($?
>> 8 ) (`command`
のステータス) で exit
する。
もし ($?
>> 8 ) が 0 なら、255 で exit
する。
eval
の中では、エラーメッセージが $@ に入り、
eval
が undefined value で終了する。
die "Can't cd to spool: $!\n" unless chdir '/usr/spool/news'; chdir '/usr/spool/news' || die "Can't cd to spool: $!\n"
EXPR
の値が改行で終わらない場合は、
スクリプトの現在の行番号および(もしあれば)入力行番号も表示され、
改行が付け加えられる。
ヒント:
メッセージに , stopped
を付け加えておくと、
at foo line 123
が付け加えられた時によりわかりやすい。
die "/etc/games is no good"; die "/etc/games is no good, stopped";
はそれぞれ次のように出力する。
/etc/games is no good at canasta line 123. /etc/games is no good, stopped at canasta line 123.
See exit.
exec(LIST)
exec LIST
LIST
の中に 1 以上の引数がある場合、
または LIST
が 1 以上の値を持つ配列の場合、
LIST
中の引数で execvp()
をコールする。
スカラー引数が 1 しかない場合、
引数にシェルのメタキャラクターがあるかどうかチェックされる。
もしあれば、parse するために全引数が /bin/sh -c
に渡される。
もしなければ、引数は単語毎に分けられ、execvp()
にそのまま渡される。
この方が効率的だからである。
注意:
exec
(および system
)は出力バッファをフラッシュしないので、
出力を失わないために $|
をセットする必要があるかもしれない。
exec '/bin/echo', 'Your arguments are: ', @ARGV; exec "sort $outfile | uniq";
本当は第一引数を実行したくないが、
プログラムをだましてその名前で実行しているように見せたい時は、
本当に走らせたいプログラム名を変数に代入し、
その変数を LIST
の前にコンマと共に指定すれば良い
(こうすると LIST
にスカラーが一つしかなくても、
LIST
が常に複数の値を持っていると解釈される)。
$shell = '/bin/csh'; exec $shell '-sh'; # ログインシェルのふりをする
exit(EXPR)
exit EXPR
EXPR
を評価し、その値で直接 exit
する。
$ans = <STDIN>; exit 0 if $ans =~ /^[Xx]/;
EXPR
を省略すると、status 0 で exit
する。
See die.
fork
fork()
コールを行う。親プロセスには子供のプロセス ID を返し、
子プロセスには 0 を返す。
注意:
両方のプロセスにおいてフラッシュされていないバッファは
フラッシュされずに残るので、
だぶって出力されるのを防ぐには、 $|
をセットする必要がある。
See $vline for $|
.
getlogin
/etc/utmp
から、現在の login
を読んで返す。
ヌルの場合は、getpwuid
を使うこと。
$login = getlogin || (getpwuid($<))[0] || "Somebody";
getpgrp(PID)
getpgrp PID
PID
のプロセスグループを返す。
getpgrp(2)
をインプリメントしていないマシンで使用すると
致命的エラーとなる。
EXPR
を省略すると、現プロセスのプロセスグループを返す。
getppid
getpriority(WHICH,WHO)
getpriority(2)
を参照のこと。)
getpriority(2)
をインプリメントしていないマシンで使用すると
致命的エラーとなる。
kill(LIST)
kill LIST
$cnt = kill 1, $child1, $child2; kill 9, @goners;
シグナルが負の場合、プロセスではなくプロセスグループを kill
する。
(System V
では、
負のプロセス番号はプロセスグループも kill
するが、互換性はない。)
シグナル名を指定してもよい。
setpgrp(PID,PGRP)
PID
にセットし、
カレントプロセスを 0 にする。
setpgrp(2)
をインプリメントしていないマシンでは致命的エラーとなる。
setpriority(WHICH,WHO,PRIORITY)
setpriority(2)
をインプリメントしていないマシンでは
致命的エラーとなる。
(setpriority(2)
を参照。)
sleep(EXPR)
sleep EXPR
sleep
EXPR
秒の間(EXPR
を省略すると、永久に)スクリプトを停止する。
プロセスに SIGALRM
を送ると interrupt できるだろう。
実際に停止した時間を返す。
おそらく alarm
と sleep
を混在させることはできないだろう。
sleep()
は alarm()
を用いてインプリメントされている場合が
多いからだ。
syscall(LIST)
syscall LIST
LIST
の最初の要素で指定するシステムコールを行う。
残りの要素はシステムコールの引数として渡される。
インプリメントされていない場合は致命的エラーとなる。
引数は以下のように解釈される。
文字列に書き込まれるどんな結果でも受け取れるように、 文字列の長さを充分取るのはプログラマの責任である。 整数の引数が数字ではなく、数であるというコンテキストで解釈されていない場合は、 数であることを示すために 0 を足す必要があるだろう。
require 'syscall.ph'; # h2ph の必要があるかもしれない syscall(&SYS_write, fileno(STDOUT), "hi there\n", 9);
system(LIST)
system LIST
exec LIST
と全く同じことをするが、
違いは最初に fork
を行い、
親プロセスは子プロセスが完了するのを待つ点である。
注意: 引数の処理は引数の数によって変わる。
返り値はプログラムの exit status で、wait()
と同じである。
実際の exit value を得るには、256
で割る必要がある。
See exec.
times
($user,$system,$cuser,$csystem) = times;
umask(EXPR)
umask EXPR
umask
umask
をセットし、変更前の値を返す。
EXPR
を省略すると、現在の値を返すだけである。
wait
terminate
するのを待ち、
死んだプロセスの PID
、または子プロセスがない時は -1 を返す。
status は $?
に返る。See waitpid.
waitpid(PID,FLAGS)
terminate
するのを待ち、
死んだプロセスの pid
を返す。
そのような子プロセスがなければ、-1 を返す。
ステータスは $?
に返る。次のようなコードを実行すると、
require "sys/wait.h"; ... waitpid(-1,&WNOHANG);
どんなプロセスに対しても non-blocking wait を実行できる。
non-blocking wait は waitpid (2)
または wait4 (2)
の
どちらかのシステムコールをサポートしているマシンでのみ実行可能である。
しかし、ある pid
を FLAGS
を 0 にして wait するのは
どこででもインプリメントされている。(perl は、
exit したがまだ perl スクリプトが取り入れ(harvest)していないプロセスの
ステータス値を覚えておくことで、システムコールのエミュレートをする。)
warn(LIST)
warn LIST
die
のようにメッセージを STDERR
に出すが、exit
しない。
accept(NEWSOCKET,GENERICSOCKET)
bind(SOCKET,NAME)
connect(SOCKET,NAME)
NAME
はソケットに適切な型のパッケージアドレスでなくてはならない。
プロセス間通信の章の例を参照のこと。See Interprocess communication.
getpeername(SOCKET)
SOCKET
コネクションの
もう一方のパックされた sockaddr
アドレスを返す。
# インターネットソケットアドレス $sockaddr = 'S n a4 x8'; $hersockaddr = getpeername(S); ($family, $port, $heraddr) = unpack($sockaddr,$hersockaddr);
getsockname(SOCKET)
SOCKET
コネクションの
こちら側のパックされた sockaddr
アドレスを返す。
# インターネットソケットアドレス $sockaddr = 'S n a4 x8'; $mysockaddr = getsockname(S); ($family, $port, $myaddr) = unpack($sockaddr,$mysockaddr);
getsockopt(SOCKET,LEVEL,OPTNAME)
listen(SOCKET,QUEUESIZE)
listen
システムコールと同じことをする。
成功すれば真、そうでなければ偽を返す。プロセス間通信の章の例を参照。
See Interprocess communication.
recv(SOCKET,SCALAR,LEN,FLAGS)
SOCKET
からLENGTH
バイトのデータを受け取り、
SCALAR
に格納する。
sender
のアドレスを返す。エラーがあると、undefined value を返す。
SCALAR
は実際に読み込んだバイト数に合わせてサイズが変わる。
同名のシステムコールと同じフラグを用いる。
send(SOCKET,MSG,FLAGS,TO)
send(SOCKET,MSG,FLAGS)
SOCKET
にメッセージを送る。同名のシステムコールと同じフラグを使う。
コネクトしていないソケットに対しては、
メッセージを送る送り先 TO
を指定しなければならない。
送った文字数を返す。エラーがあった場合は undefined を返す。
setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)
OPTVAL
に undef
を指定することができる。
shutdown(SOCKET,HOW)
HOW
で示す manner でソケットコネクションをシャットダウンする。
HOW
は同名のシステムコールと同じように解釈される。
socket(SOCKET,DOMAIN,TYPE,PROTOCOL)
SOCKET
に結び付ける。
DOMAIN
、TYPE
、PROTOCOL
には
同名のシステムコールと同じものを指定する。
perl ライブラリファイルから手軽に適切な値を得るためには、
sys/socket.h
に対して h2ph
を走らせる必要があるかも知れない。
成功すれば真を返す。プロセス間通信の章の例を参照。 See Interprocess communication.
socketpair(SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL)
DOMAIN
に、
指定した TYPE
の無名のソケットのペアを作成する。
DOMAIN
、TYPE
、PROTOCOL
は
同名のシステムコールと同じものを指定する。
インプリメントされていない場合は、致命的エラーとなる。
成功すれば真を返す。
msgctl(ID,CMD,ARG)
msgctl
を呼ぶ。
CMD
が &IPC_STAT
である場合は、
ARG
は変数でなければならず、これに msqid_ds
構造体が返ってくる。
ioctl
と同様の値を返す。
すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真
、
その他の場合は実際の返り値が返る。
msgget(KEY,FLAGS)
msgget
を呼ぶ。
メッセージキュー ID を返す。エラーがあれば undefined の値を返す。
msgsnd(ID,MSG,FLAGS)
msgsnd
を呼び、
メッセージキュー ID が ID
のメッセージにメッセージ MSG
を送る。
MSG
の始まりはメッセージ型が long integer でなければならない
(これは pack("L", $type)
で作成できる)。
成功すれば真、エラーがあれば偽を返す。
msgrcv(ID,VAR,SIZE,TYPE,FLAGS)
msgrcv
を呼び、
メッセージキュー ID
からのメッセージを受け取って
変数 VAR
に最大メッセージサイズ SIZE
で格納する。
注意: メッセージを受け取った場合、
メッセージ型は VAR
に格納した最初のものになる。
また、VAR
の最大サイズは SIZE
+ メッセージ型のサイズになる。
成功すれば真を返し、エラーがあれば偽を返す。
semctl(ID,SEMNUM,CMD,ARG)
semctl
を呼ぶ。
CMD
が &IPC_STAT
または &GETALL
なら、
ARG
は変数でなければならず、
これに semid_ds
構造体またはセマフォ値の配列が返る。
ioctl
と同様の値を返す。
すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真
、
その他の場合は実際の返り値が返る。
semget(KEY,NSEMS,SIZE,FLAGS)
semget
を呼ぶ。セマフォ ID を返す。
エラーの場合は undefined の値を返す。
semop(KEY,OPSTRING)
semop
を呼ぶ。
これにより、signaling
、waiting
などの
セマフォ処理を行うことができる。
OPSTRING
は、
semop
構造体の配列を pack
したものでなければならない。
semop
構造体は、
pack("sss", $semnum, $semop, $semflag)
で作ることができる。
セマフォ処理の数は OPSTRING
の長さで暗黙の内に指定される。
成功すれば真、エラーがあれば偽を返す。
例: 次のコードはセマフォ ID $semid
のセマフォ $semnum
を待つ。
$semop = pack("sss", $semnum, -1, 0); die "Semaphore trouble: $!\n" unless semop($semid, $semop);
セマフォにシグナルを送るには、-1
を 1
に置き換えればよい。
shmctl(ID,CMD,ARG)
shmctl
を呼ぶ。
CMD
が &IPC_STAT
である場合は、
ARG
は変数でなければならず、
これに shmid_ds
構造体が返ってくる。
ioctl
と同様の値を返す。
すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真
、
その他の場合は実際の返り値が返る。
shmget(KEY,SIZE,FLAGS)
shmget
を呼ぶ。共有メモリ ID を返す。
エラーがあれば undefined の値を返す。
shmread(ID,VAR,POS,SIZE)
shmwrite(ID,STRING,POS,SIZE)
ID
に、
位置 POS
から サイズ SIZE
にわたって attach し、
copy in/out し、detach することで読み込み/書き込みを行う。
読み込みの際には、VAR
は変数でなければならず、
読み込まれるデータが格納される。
STRING
が短い場合は、
SIZE
バイトを満たすためヌルが書かれる。
成功すれば真、エラーがあれば偽を返す。
以下の * の部分には、各システムファイルに対応して、
/etc/passwd → pw /etc/group → gr /etc/hosts → host /etc/networks → net /etc/protocols → proto /etc/services → serv
がそれぞれ入る。
getpwnam(NAME)
, getgrnam(NAME)
,
gethostbyname(NAME)
, getnetbyname(NAME)
,
getprotobyname(NAME)
, getservbyname(NAME,PROTO)
getpwuid(UID)
, getgrgid(GID)
gethostbyaddr(ADDR,ADDRTYPE)
, getnetbyaddr(ADDR,ADDRTYPE)
,
getprotobynumber(NUMBER)
, getservbyport(PORT,PROTO)
getpwent
, getgrent
, gethostent
, getnetent
,
getprotoent
, getservent
setpwent
, setgrent
, sethostent(STAYOPEN)
,
setnetent(STAYOPEN)
,
setprotoent(STAYOPEN)
,setservent(STAYOPEN)
endpwent
, endgrent
, endhostent
, endnetent
,
endprotoent
, endservent
これらのルーチンはシステムライブラリ内の同様の関数と同じ動作をする。
get
ルーチンの返り値は以下の通りである。
($name,$passwd,$uid,$gid, $quota,$comment,$gcos,$dir,$shell) = getpw... ($name,$passwd,$gid,$members) = getgr... ($name,$aliases,$addrtype,$length,@addrs) = gethost... ($name,$aliases,$addrtype,$net) = getnet... ($name,$aliases,$proto) = getproto... ($name,$aliases,$port,$proto) = getserv...
getgr
... が返す値 $members
は
グループのメンバーのログイン名のリストをスペースで区切ったものである。
gethost
... が返す値 @addrs
は
対応するシステムライブラリをコールして得られる raw address のリストである。
Internet の domain では、各アドレスは長さ 4 バイトで、
次のようにして unpack
できる。
($a,$b,$c,$d) = unpack('C4',$addr[0]);
caller(EXPR)
caller
($package,$filename,$line) = caller;
EXPR
を指定すると、
デバッガがスタックトレースを出力するために使用する情報も返す。
EXPR
の値が、
現在のサブルーチンの前に call
フレームがいくつあるかを示す。
defined(EXPR)
defined EXPR
EXPR
が real value を持つかどうかを示す boolean 値を返す。
ファイルの終わり、初期化されていない変数、
システムエラーなどの例外的な状況では、define されていない値を返す操作が多い。
この関数は本当のヌル文字列を返すかも知れない操作について、
define されていないヌル文字列と define されているヌル文字列を区別してくれる
(特に配列の要素を参照する操作について)。
また、配列やサブルーチンが存在するかどうかチェックすることもできる。 予め define されていない変数を使用しても、期待された動作は保証されない。
print if defined $switch{'D'}; print "$val\n" while defined($val = pop(@ary)); die "Can't readlink $sym: $!" unless defined($value = readlink $sym); eval '@foo = ()' if defined(@foo); die "No XYZ package defined" unless defined %_XYZ; sub foo { defined &$bar ? &$bar(@_) : die "No bar"; }
See undef.
dump LABEL
undump
プログラムを使って
実行可能なバイナリ(プログラムの先頭であらかじめ変数が初期化されている)を
作ることができるようにしたものである。
できたバイナリを実行すると goto LABEL
を最初に実行する
(goto
がもつ制限は全て適用される)。
dump
は コアダンプをはさんだ goto
+ 再スタート と考えればよい。
LABEL
を省略すると、プログラムの先頭から再スタートする。
警告: dump
の時点でオープンされていたファイルはすべて
プログラムが再生した時にはオープンされない
(perl の側からみると混乱するため)。
-u
オプションも参照のこと。See Option.
#!/usr/bin/perl require 'getopt.pl'; require 'stat.pl'; %days = ( 'Sun',1, 'Mon',2, 'Tue',3, 'Wed',4, 'Thu',5, 'Fri',6, 'Sat',7); dump QUICKSTART if $ARGV[0] eq '-d'; QUICKSTART: do Getopt('f');
local(LIST)
eval
・do
にローカルであると宣言する。リスト中の全要素は左辺値でなければならない。
local
は LIST
中の変数の値をスタックに保存し、
ブロック・サブルーチン・eval
から抜ける時に元に戻す。
このため、呼ばれたサブルーチンではローカル変数は参照できるが、
グローバルな変数は参照できないことになる。
LIST
は希望により値を代入することができる。
これによりローカル変数を初期化できる。
(ある変数について初期化を指示しない場合、値はundefined
で作成される。)
通常、サブルーチンへのパラメータに名前を付けるのに用いる。
sub RANGEVAL { local($min, $max, $thunk) = @_; local($result) = ''; local($i); # $thunk は $i を参照すると仮定している for ($i = $min; $i < $max; $i++) { $result .= eval $thunk; } $result; } if ($sw eq '-v') { # グローバルな配列でローカルな配列を初期化 local(@ARGV) = @ARGV; unshift(@ARGV,'echo'); system @ARGV; } # @ARGV は保存される # 連想配列に一時的に数字を付加する if ($base12) { # (注意: これが効率がよいわけではない!) local(%digits) = (%digits,'t',10,'e',11); do parse_num(); }
注意:
local()
は run-time コマンドであり、ループでは毎回実行される。
このためループから抜けて解放するまで、毎回スタックを消費する。
q/STRING/
qq/STRING/
qx/STRING/
q
は一般化されたシングルクォートであり、
qq
は一般化されたダブルクォートである。
qx
は一般化されたバッククォートである。
/
の代わりに
改行を含むアルファベット・数字でない任意の文字を delimiter として使える。
delimiter が (
または {
の場合は、
最後の delimiter は対応する )
、}
となる。
( )
や }
が文字列に埋め込まれる場合は
従来通りバックスラッシュをつける必要がある。)
$foo = q!I said, "You said, 'She said it.'"!; $bar = q('This is it.'); $today = qx date ; $_ .= qq *** The previous line contains the naughty word "$&".\n if /(ibm|apple|awk)/; # :-)
require(EXPR)
require EXPR
require
EXPR
、
または EXPR
が指定されていない時は $_
で示される
ライブラリファイルをインクルードする。
次のサブルーチンと同じ意味がある。
sub require { local($filename) = @_; return 1 if $INC{$filename}; local($realfilename,$result); ITER: { foreach $prefix (@INC) { $realfilename = "$prefix/$filename"; if (-f $realfilename) { $result = do $realfilename; last ITER; } } die "Can't find $filename in \@INC"; } die $@ if $@; die "$filename did not return true value" unless $result; $INC{$filename} = $realfilename; $result; }
注意: 同じ名前ではファイルを二度インクルードすることはできない。
See INC for @INC
.
reset(EXPR)
reset EXPR
reset
continue
ブロックの中で、
変数を clear し、?? search
をリセットして
再び使用可能にするために用いる。
EXPR
は文字のリストとして解釈される(ハイフンは range を考慮する)。
この文字のどれかで始まる変数および配列は全て元の状態にリセットされる。
EXPR
を省略すると、
one-match search (?pattern?
)が match に再リセットされる。
カレントのパッケージ内の変数・検索のみをリセットする。
常に 1 を返す。See ?PATTERN?.
reset 'X'; # reset all X variables reset 'a-z'; # reset lower case variables reset; # just reset ?? searches
注意:
A-Z
でリセットするのは勧められない。
なぜなら、配列 ARGV
や ENV
の内容を消すからである。
dbm
連想配列をリセットしても dbm
ファイルを変更しない。
(が、perl がキャッシュした全エントリをフラッシュすれば、変更する。
こうすれば、dbm
ファイルを共有している時に便利である。
便利でないかも知れないが。)
scalar(EXPR)
EXPR
を強制的にスカラーのコンテキストで解釈させ、その値を返す。
undef(EXPR)
undef EXPR
undef
EXPR
(左辺値でなくてはならない)の値を undef
する。
スカラー値、配列すべて、サブルーチン名(&
を用いる)
に対してのみ用いること。
(undef
はおそらく定義されている変数や dbm
配列値の多くについて
期待する動作をしないであろう。)
常に undefined value を返す。
EXPR
を省略しても良いが、この場合何も undefine
されず、
例えばサブルーチンから返る時に undefined value を得ることができる。
undef $foo; undef $bar{'blurfl'}; undef @ary; undef %assoc; undef &mysub; return (wantarray ? () : undef) if $they_blew_it;
wantarray
return wantarray ? () : undef;
perl の演算子の結合規則と優先度は次の通りである。
優先度 結合規則 演算子 低い なし print printf exec system sort reverse chmod chown kill unlink utime die return 左から右 , 右から左 = += -= *= など 右から左 ?: なし .. 左から右 || 左から右 && 左から右 | ^ 左から右 & なし == != <=> eq ne cmp なし < > <= >= lt gt le ge なし chdir exit eval reset sleep rand umask なし -r -w -x など 左から右 << >> 左から右 + - . 左から右 * / % x 左から右 =~ !~ 右から左 ! ~ および単項演算子 - 右から左 ** なし ++ -- 高い 左から右 '('
リストを引数にとる演算子(print
その他)や
単項演算子すべて(chdir
など)の直ぐ後ろ(同じ行)に左括弧がある場合、
通常の関数呼び出しと同じように演算子と括弧の中の引数は最も高い優先度を持つ。
(例)
chdir $foo || die; # (chdir $foo) || die chdir($foo) || die; # (chdir $foo) || die chdir ($foo) || die; # (chdir $foo) || die chdir +($foo) || die; # (chdir $foo) || die
しかし、*
は ||
よりも優先度が高いので、
chdir $foo * 20; # chdir ($foo * 20) chdir($foo) * 20; # (chdir $foo) * 20 chdir ($foo) * 20; # (chdir $foo) * 20 chdir +($foo) * 20; # chdir ($foo * 20) rand 10 * 20; # rand (10 * 20) rand(10) * 20; # (rand 10) * 20 rand (10) * 20; # (rand 10) * 20 rand +(10) * 20; # rand (10 * 20)
括弧がない場合、print
, sort
, chmod
といった
リストを引数に持つ演算子の優先度は
演算子の左側を見るか右側を見るかによって非常に高いか、
非常に低いかのどちらかである。
たとえば、次の例で、
@ary = (1, 3, sort 4, 2); print @ary; # prints 1324
sort
の右側にあるコンマは sort
の前に評価されるが、
左側のコンマは sort
の後で評価される。
言い換えると、リストを引数に取る演算子は
それに続く引数をすべて自分のものにしてしまい、
その後は前にある expression に単純に従う傾向がある。
括弧には注意しなければならない。
# これらは print を評価する前に exit を評価してしまう print($foo, exit); # 明らかにこれは正しくない print $foo, exit; # これでもない # これらは exit を評価する前に print を実行する (print $foo), exit; # これが正しい print($foo), exit; # またはこれ。 print ($foo), exit; # これでも正しい。
また、
print ($foo & 255) + 1, "\n";
はおそらく見た目の動作はしない。
サブルーチンは次のように宣言する。
sub NAME BLOCK
渡した引数は全て配列 @_
、
すなわち $_[0]
, $_[1]
,... に入る。
配列 @_
はローカルな配列だが、
その値は実際のスカラーパラメータへの参照となっている。
サブルーチンの返り値は最後に評価した expression の値であり、
配列値でもスカラー値でもよい。
また、値を返してサブルーチンから抜けることを指示するために、
return
宣言を使ってもよい。
ローカル変数を作る方法は、local
演算子の項を参照のこと。
See local.
サブルーチンは do
演算子または &
演算子を用いてコールする。
例:
sub MAX { local($max) = pop(@_); foreach $foo (@_) { $max = $foo if $max < $foo; } $max; } ... $bestday = &MAX($mon,$tue,$wed,$thu,$fri);
例:
# 行を受け取り、スペース類で始まる継続行を結合する
sub get_line {
$thisline = $lookahead;
line: while ($lookahead = <STDIN>) {
if ($lookahead =~ /^[ \t]/) {
$thisline .= $lookahead;
}
else {
last line;
}
}
$thisline;
}
$lookahead = <STDIN>; # 最初の行を得る
while ($_
= do get_line()) {
...
}
引数に名前をつけるには、ローカルなリストへ配列代入を行う。
sub maybeset { local($key, $value) = @_; $foo{$key} = $value unless $foo{$key}; }
こうすることで、参照呼び出しが値呼び出しになる。 なぜなら、代入により値がコピーされるからである。
サブルーチンは再帰的に呼び出してもよい。
サブルーチンを &
形式で呼び出す場合は引数のリストはつけなくてもよい。
これを省略すると、サブルーチンの配列 @_
のセットアップは行われない。
コールを行った時の配列 @_
がサブルーチンから参照できる。
do foo(1,2,3); # 3 つの引数を渡す &foo(1,2,3); # 同じ do foo(); # ヌルリストを渡す &foo(); # 同じ &foo; # 引数を渡さない --- より効率がよい
サブルーチンへ配列の値を渡すのではなく、 その名前を渡して、サブルーチンがローカルなコピーに対してではなく グローバルな配列を変更できるようにしたい時があるだろう。
perl では名前を持つ全てのオブジェクトに対して、
その名前の前に *
をつけることで参照することができる: *foo
。
これが評価されると、その名前を持つ、
ファイルハンドル・フォーマット・サブルーチンを含む
全オブジェクトを表すスカラー値となる。
local()
演算内で代入を行うと、
その名前がそれに代入された *
値 を参照するようになる。例えば、
sub doubleary { local(*someary) = @_; foreach $elem (@someary) { $elem *= 2; } } do doubleary(*foo); do doubleary(*bar);
*name
への代入は
現在のところ local()
の場合しかお勧めできない。
実際のところ、*name
への代入はどこでもできるのだが、
以前に行った *name
への参照が永遠に尾を引く(may be stranded forever)
可能性がある。これは困ったことかもしれないし、そうでないかもしれない。
スカラー値は何もしなくても参照渡しである。
すなわち、このメカニズムを用いなくても、
関心のある $_[nnn]
への明示的な参照を行うことで
変更を行うことが可能である。
配列の全要素をスカラー値として渡すことで配列要素の変更は可能であるが、
push
、pop
や配列の大きさを変える操作には、
*
メカニズムを使わなければならない。
*
メカニズムはどのような場合でも効率がよりよいだろう。
*name
の値は出力不可能なバイナリデータを含むので、
print
や printf
、
sprintf
の %s
への引数として用いると
出力をきれいに行うため、*name
という値になる。
配列を変更したくない場合でも、 このメカニズムは複数の配列を一つのリストで渡すのに便利である。 なぜなら、通常、リストメカニズムは全配列値を一つにマージするため、 それを個々の配列に分けることができないからである。
パターンマッチングで用いられるパターンは、 Version 8 の regexp ルーチンで使用できるものと同じものである。 (実は、ヘンリースペンサーの再配布自由な V8 ルーチンを使っている。)
これに加えて、以下のマッチングが使える。
\w : アルファベット文字( "_" を含む) \W : 非アルファベット文字 \b : 単語の境界 \B : 非単語境界 \s : スペース文字(whitespace character) \S : 非スペース文字 \d : 数字 \D : 非数字
\w
、\s
、\d
を character class の中で用いても良い。
\n
、\r
、\f
、\t
、\NNN
は
通常と同じ意味を持つ。
\b
は単語境界ではなくバックスペースを表す。
|
で区切る。
括弧構造 (
... )
を使うと、
\数字
がその数字番目の文字列にマッチする。
(パターンの外では、
数字の前に \
ではなく $
を常に用いなければならない。
$数字
と $`
、$&
、$'
の有効範囲は
括弧で囲まれたブロックや eval
文字列、
または次のパターンマッチまでである。
\数字
記述は現在のパターンの外でも使えることがあるが、
それに頼るべきではない。)
括弧はいくつ用いてもよい。
9 より多くの部分文字列がある場合は、
$10
,$11
... が対応する部分文字列を参照する。
パターンの中では、\10
,\11
... が部分文字列を後方参照する
(少なくともその数の左括弧が後方参照箇所の前にある場合。
なければ以前のバージョンとのコンパチビリティのため、
\10
は \010
すなわちバックスペースと同じ、
\11
は \011
すなわちタブと同じ、となる。
\1
から \9
までは常に後方参照である。)。
$+
は最後にマッチした括弧を返す。
$&
はマッチした文字列全体を返す。
($0
は同じものを返していたが、現在はそうではない。)
$`
はマッチした文字列の前の全文字を返す。
$'
はマッチした文字列の後の全文字を返す。
(例)
s/^([^ ]*) *([^ ]*)/$2 $1/; # 最初の 2 単語を入れ替える if (/Time: (..):(..):(..)/) { $hours = $1; $minutes = $2; $seconds = $3; }
デフォルトでは、文字 ^
は文字列の最初のみ、
文字 $
は文字列の最後
(または最後の改行文字の前の文字)のみに一致することが保証されていて、
また、perl は文字列が 1 行しか含んでいないと仮定して最適化している。
改行文字が複数ある場合の ^
と $
の挙動は矛盾する
(beinconsistent)。
しかし、文字列を複数行のバッファとして扱い、
^
が文字列中の全ての改行文字の後にマッチし、
$
が全ての改行文字の前にマッチするようにしたい場合もあるだろう。
これを実現するには、少しオーバーヘッドを要するが、
$*
変数に 1 をセットすれば良い。
この変数を 0 に戻せば、perl は本来の挙動に戻る。See $*.
複数行の置換を容易にするために、文字 .
は改行文字にマッチしない
($*
が 0 の時でも)。特に、次の例では、$_
に改行文字を残す。
$_ = <STDIN>; s/.*(some_string).*/$1/;
改行文字がいらないなら、次のどれかを試せば良い。
s/.*(some_string).*\n/$1/; s/.*(some_string)[^\000]*/$1/; s/.*(some_string)(.|\n)*/$1/; chop; s/.*(some_string).*/$1/; /(some_string)/ && ($_ = $1);
正規表現の各要素の後に、
中括弧で囲んだ数字を {n,m}
の形で付けることができる。
ここで n
はその要素にマッチする最小限の回数、
m
は最大限の回数を表す。
{n}
の形は {n,n}
と同等であり、
n
回ちょうどにマッチする。
{n,}
の形は n
以上の回数にマッチする
(中括弧が別のコンテキストで使われた場合は、中括弧は通常の文字として扱われる)。
修飾子 *
は {0,}
、修飾子 +
は {1,}
、
修飾子 ?
は {0,1}にそれぞれ等しい。
n
や m
の大きさには制限はないが、
大きな数を使うとより多くのメモリーを消費する。
perl では、例えば \b
、\w
、\n
のように、
バックスラッシュを前に付けるメタキャラクターは
すべてアルファベットであることに気がつくだろう。
他の正規表現言語と違い、
アルファベットでない文字にバックスラッシュをつけることはないので、
\\
、 \(
、 \)
、 \<
、 \>
、 \{
、
や \}
のようなものは全て文字通りに解釈され、
メタキャラクターとは解釈されない。
これにより、メタキャラクターを含んでいるのではないかと心配な文字列を
パターンとして使用することが容易になる。
アルファベットでない文字は単純に使用して良い。
$pattern =~ s/(\W)/\\$1/g;
write
演算子で使う出力レコードフォーマットは以下のように宣言する。
format NAME = FORMLIST .
NAME
を省略すると、STDOUT
が定義される。
FORMLIST
は複数行からなり、行はそれぞれ 3 種類のどれかである。
picture
行。
picture
行に値を与える引数行。
picture
行は行内の値が置換される特定のフィールドを除いて
見た目そのままに出力される。
picture
フィールドは全て @
または ^
で始まる。
@
フィールド(配列を表す @
と混乱しないように)は通常の場合、
^
フィールドは複数行テキストブロックの
初歩的な filling を行うためのものである。
フィールドの長さは文字 <
>
|
で埋めることで表す。
これらはそれぞれ左寄せ、右寄せ、センタリングを指示する。
右寄せについては、#
(に .
をつけてもよい)を使って
数値フィールドであることを指定してもよい。
(@ の代わりに ^ を使うと、そのフィールドが undefined の場合ブランクになる。)
これらのフィールドに指定された値に改行が入っている場合は、
改行までのテキストのみが出力される。
特殊なフィールド @*
は複数行の値を出力するのに用いる。
これは一行にそれだけしか指定できない。
値はその次の行で指定する。
順番は picture
フィールドのものと同じにする。
値はコンマで区切らなければならない。
@
ではなく、
^
で始まる picture
フィールドは特別に扱われる。
指定する値はテキスト文字列を値として持つスカラー変数の名前でなければならない。
perl は可能なかぎりのテキストをフィールドに与え、変数の先頭からそれを取り除く。
これは次にその変数が参照された時にテキストの続きを表示するためである。
通常、テキストブロックを出力するには垂直なスタックの中にフィールドをいくつか書く。
最後のフィールドを ...
で終わることもできる。
こうすればテキストが全部入りきらない場合に ...
が出力に現れる。
変数 $:
を好みの文字のリストに変更することで
テキストを分割することが可能な文字を変えることができる。See $colon for $:
.
フォーマットされるテキストが短い場合、
^
フィールドを使うと可変長レコードができるので、
行のどこかに文字 ~
を入れることで空行の出力を抑制することができる。
(見易さを考えると、通常、可能ならば先頭に入れるべきである。)
~
は出力においてスペースに変換される。
一つ目に続けて二つ目の ~
を入れると、
行中の全フィールドがなくなるまでその行を繰り返す?。
(@
フィールドを使う場合、それに与える expression は
永遠に同じ値であるようなものにするべきではない。)
例:
# /etc/passwd ファイルのレポート format STDOUT_TOP = Passwd File Name Login Office Uid Gid Home ------------------------------------------------------------------ . format STDOUT = @<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<< $name, $login, $office,$uid,$gid, $home # バグレポート形式 format STDOUT_TOP = Bug Reports @<<<<<<<<<<<<<<<<<<<<<<< @||| @>>>>>>>>>>>>>>>>>>>>>>> $system, $%, $date ------------------------------------------------------------------ . format STDOUT = Subject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $subject Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $index, $description Priority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $priority, $date, $description From: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $from, $description Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $programmer, $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<... $description .
同じ出力チャンネルに対して write
を使って
出力を混在させることは可能であるが、
$-
(ページに残っている行)を自分で扱わねばならない。
See $-.
ほとんどが空白であるようなフィールドを出力する場合は、
レコードの間で reset
演算子を使うことを考えた方がよい。
より効率的であるだけでなく、
フィールドを増やして、初期化するのを忘れてしまうというバグを防げる。
See reset.
perl のプロセス間通信の能力はバークレイのソケット機構に基づいている。 ソケットがないのなら、この項は読まなくてよい。
関数は対応するシステムコールと同じ名前がついているが、 引数は二つの理由で違う場合がある。 まず、perl のファイルハンドルは C のファイルディスクリプタとは働きが違う。 次に、perl は文字列長を知っているので、その情報は渡さなくてよい。
以下にクライアントのサンプルを示す(テストしていない)。
($them,$port) = @ARGV; $port = 2345 unless $port; $them = 'localhost' unless $them; $SIG{'INT'} = 'dokill'; sub dokill { kill 9,$child if $child; } require 'sys/socket.ph'; $sockaddr = 'S n a4 x8'; chop($hostname = `hostname`); ($name, $aliases, $proto) = getprotobyname('tcp'); ($name, $aliases, $port) = getservbyname($port, 'tcp') unless $port =~ /^\d+$/; ($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname); ($name, $aliases, $type, $len, $thataddr) = gethostbyname($them); $this = pack($sockaddr, &AF_INET, 0, $thisaddr); $that = pack($sockaddr, &AF_INET, $port, $thataddr); socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!"; bind(S, $this) || die "bind: $!"; connect(S, $that) || die "connect: $!"; select(S); $| = 1; select(stdout); if ($child = fork) { while (<>) { print S; } sleep 3; do dokill(); } else { while (<S>) { print; } }
そしてこれがサーバーである。
($port) = @ARGV; $port = 2345 unless $port; require 'sys/socket.ph'; $sockaddr = 'S n a4 x8'; ($name, $aliases, $proto) = getprotobyname('tcp'); ($name, $aliases, $port) = getservbyname($port, 'tcp') unless $port =~ /^\d+$/; $this = pack($sockaddr, &AF_INET, $port, "\0\0\0\0"); select(NS); $| = 1; select(stdout); socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!"; bind(S, $this) || die "bind: $!"; listen(S, 5) || die "connect: $!"; select(S); $| = 1; select(stdout); for (;;) { print "Listening again\n"; ($addr = accept(NS,S)) || die $!; print "accept ok\n"; ($af,$port,$inetaddr) = unpack($sockaddr,$addr); @inetaddr = unpack('C4',$inetaddr); print "$af $port @inetaddr\n"; while (<NS>) { print; print NS; } }
以下の名前の変数は perl において特別な意味をもつ。
このうち幾つかはアルファベットの名前を持たせても良かったのだが、
全変数を a-zA-Z
でリセットすることができるようにするため、
そうはしなかった。
このため、わけの分からないシンボル名で苦労しなければならない。
ほとんどのものはそれなりに覚え易いものまたはシェル変数と似たものにしてある。
変数名 ノード名 簡単な説明
予約変数のサブノード ――――――――――――
$_
: 入力およびパターン検索におけるデフォルト。
次の式のペアはそれぞれ等価である。
while (<>) { ... # only equivalent in while! while ($_ = <>) { ... /^Subject:/ $_ =~ /^Subject:/ y/a-z/A-Z/ $_ =~ y/a-z/A-Z/ chop chop($_)
覚え方:
?
( underline is understood in certain operations.)
$.
: 最後に読み込みを行ったファイルハンドルの現在の行番号。
参照のみ可能。ファイルハンドルを明示的にクローズした時のみリセットされる。
<>
は明示的なクローズを行わないので、
ARGV
ファイルを読んでいくと、行番号はどんどん増加する。
( eof
の例を参照。)See eof.
覚え方:
多くのプログラムにおいて .
は現在の行番号を示すために用いられる。
$/
: 入力レコードのセパレータ。デフォルトは newline 。
awk の変数 RS
のような働きをする。
ヌル文字列をセットすると、ブランク行を区切りとする点も同じである。
複数文字からなる文字列をセットして、
複数文字のデリミッタにマッチさせることも可能である。
覚え方:
/
は詩を引用する時、行の境界を分けるのに使われる。
$,
: コンマで区切った print
関数の引数の出力セパレータ
通常、
print
はコンマで区切られたフィールドをそのまま(何もつけずに)出力する。
awk のように出力するには、awk 変数 OFS
にセットする値
(フィールド間を何で区切るか)をこの変数にセットする。
覚え方:
print
関数において ,
で区切ると出力される文字。
$"
: 配列値を "" で囲んだ時に要素間に入るセパレータ
配列値が "
で囲まれた文字列に変換される時
(または同様に変換される文字列)に適用される点を除いて、
$,
と同じ。デフォルトはスペース。
覚え方:
明らかだと思うのだが。
$\
: print 関数の最後に出力するセパレータ
通常、print
はコンマで区切られたフィールドを出力する時、
最後に newline やレコードセパレータをつけずに出力する。
awk のように出力するには、awk の ORS
変数にセットする値
(print
の最後に何を出力するか)をこの変数にセットする。
覚え方:
print
の最後に \n
をつける替わりに $\
をセットする。
また、\
は /
と似ているが、
それは"逆に" perl からデータを受け取る時に使う。
$#
: 数字の出力フォーマット
この変数は、
awk の OFMT
変数を不完全にエミュレートしようとしたものである。
だが、awk と perl で"何が数値か"を判断する際に違いが出ることがある。
また、初期値は %.6g
ではなく %.20g
であるので、
awk と同じ出力を得るには、$#
をセットする必要がある。
覚え方:
#
は数を表す。
$%
: 現在セレクトされている出力チャンネルの現在のページ番号。
覚え方:
nroff
において %
はページ番号である。
$=
: 現在セレクトされている出力チャンネルの現在のページ長さ
(出力可能行数)。
デフォルトは 60。
覚え方:
=
は水平な線からできている。
$-
: 現在セレクトされている出力チャンネルのページに残っている行数。
覚え方:
ページの行数 - 出力した行数。
$~
: 現在セレクトされている出力チャンネルの
現在のレポートフォーマットの名前。
デフォルトはファイルハンドル名。
覚え方:
$^
の兄弟。
$^
: 現在セレクトされている出力チャンネルの現在のページトップの名前。
デフォルトはファイルハンドル名に "_TOP"
をつけたもの。
覚え方:
ページのトップを指している。
$|
: write
または print
の後にフラッシュを行うか否か
非 0 にセットすると、現在セレクトされている出力チャンネルに対する
全ての write
または print
の後にフラッシュを行う。
デフォルトは 0 である。
STDOUT
は端末への出力は行バッファリングされ、
それ以外はブロックバッファリングされることに注意。
この変数をセットすると、perl スクリプトを rsh
の下で走らせて、
何が起こっているかをその時に見たい場合など、パイプに出力する際に便利である。
覚え方:(?)
(when you want your pipes to be piping hot.)
$$
: スクリプトを走らせている perl のプロセス番号。
覚え方:
シェルと同じ。
$?
: 最後のパイプのクローズ、`コマンド`
、
system
関数から返ったステータス。
これはシステムコール wait()
から返ったステータスワードであり、
サブプロセスの実際の終了値は $? >> 8
であることに注意。
$? & 255
により、プロセスが終了する原因となったシグナル(もしあれば)、
およびコアダンプがあったかどうかが得られる。
覚え方:
sh
および ksh
と同じ。
$&
: 最後のパターンマッチでマッチした文字列。
ブロックや現在のブロックで囲まれている eval
の中のマッチは
全くカウントしていない。
覚え方:
あるエディタにおける &
と同じ。
$`
: 最後のパターンマッチでマッチした文字列の前の文字列。
ブロックや現在のブロックで囲まれている eval
の中のマッチは
全くカウントしていない。
覚え方:
`
は引用文字列の前に来ることが多い。
$'
: 最後のパターンマッチでマッチした文字列の後に続く文字列。
ブロックや現在のブロックで囲まれている eval
の中のマッチは
全くカウントしていない。
覚え方:
'
は引用文字列の後に来ることが多い。
(例)
$_ = 'abcdefghi'; /def/; print "$`:$&:$'\n"; # prints abc:def:ghi
$+
: 最後の検索パターンにおいてマッチした最後の括弧。
複数候補のパターン検索で、 どちらがマッチしたかがわからないときに便利である。
(例)
/Version: (.*)|Revision: (.*)/ && ($rev = $+);
覚え方: ?
be positive and forward looking.
$*
: 複数行パターンマッチングを行うか否か
パターンマッチを最適化するために、 文字列内で複数行マッチングを行う時 1 にセットし、 文字列が 1 行しか含まないことを perl に知らせるために 0 をセットする。
$*
を 0 にしていると、
newline を複数含む文字列に対するパターンマッチは混乱した結果を返すことがある。
デフォルトは 0 である。
覚え方:
*
は複数にマッチする。
注意: この変数は ^
や $
の解釈にのみ影響を与える。
改行文字は $* == 0
であっても検索できる。
$0
: 実行している perl スクリプトのファイル名。
$0 に代入を行なうと、ps(1) プログラムが参照する引数領域を変更する。
覚え方:
sh
や ksh
と同じ。
$数字
: 最後に行ったパターンマッチの括弧の数に対応したサブパターン。
既に実行を終えたネストブロック内のパターンはカウントされない。
覚え方:
\数字
に似ている。
$[
: 配列の最初の要素やサブストリングの最初の文字の添え字。
デフォルトは0 だが、perl を awk (または Fortran)のように動かしたければ、
添え字を使う時、
index()
や substr()
を実行する時に 1 にセットすればよい。
覚え方:
[
は添え字の始まり。
$]
: perl -v
を入力した時に出力される文字列。
スクリプトを実行している perl インタプリタが
正しいバージョンであるかどうかをスクリプトの最初で調べるのに使える。
数値のコンテキストで用いると、version + patchlevel / 1000
を返す。
(例)
# getc が使えるかどうか調べる ($version,$patchlevel) = $] =~ /(\d+\.\d+).*\nPatch level: (\d+)/; print STDERR "(No filename completion available.)\n" if $version * 1000 + $patchlevel < 2016;
または、数値として用いると、
warn "No checksumming!\n" if $] < 3.019;
覚え方: ?
(Is this version of perl in the right bracket?)
$;
: 多次元配列のエミュレーションの際の添え字の区切り。
連想配列の要素を
$foo{$a,$b,$c}のように参照すれば、それは実際は
$foo{join($;, $a, $b, $c)}
を意味する。
しかし、
@foo{$a,$b,$c} # a slice--note the @
は駄目である。なぜなら、これは
($foo{$a},$foo{$b},$foo{$c})
を意味するからである。
デフォルトは \034
で、awk の SUBSEP
と同じである。
連想配列のキーにバイナリーデータが含まれる場合は、
$;
として安全な値はない。
覚え方:
コンマ(文法的な添え字区切り)はセミ-セミコロンである。
いや、ちょっと具合が悪いのはわかってるんだけど、
$,
はもうほかのもっと重要なものに使ってしまったからね。
$!
: errno の現在値またはシステムエラー文字列
数値のコンテキストで使うと、
通常出される警告と共に errno
の現在の値を返す。
(つまり、システムエラーを示す特定のエラーが返ったのでないかぎり、
$!
の値は意味がないことになる。)
文字列のコンテキストで使うと、システムエラー文字列を返す。
errno
をセットするために $!
に代入することができる。
例えば、$!
にエラー n に対応する文字列を入れて返す場合、
または die
関数の終了値をセットしたい場合、など。
覚え方:
What just went bang?
$@
: 最後に行った eval
コマンドのシンタックスエラーメッセージ。
ヌルならば、最後に行った eval
は解析・実行が正しく行われたことを示す。
(起動した処理は普通に [in a normal fashion] 失敗したかもしれないが)
覚え方:
Where was the syntax error "at"?
$<
: プロセスの実 uid。
覚え方:
setuid スクリプトを走らせている場合、君はどこから来たのか?
$>
: プロセスの実効 uid。
(例)
$< = $>; # 実 uid を実効 uid にセットする ($<,$>) = ($>,$<); # 実 uid と実効 uid を入れ替える
覚え方:
setuid スクリプトを走らせている場合、君はどこへ行ったのか?
(注意)
$<
や $>
は、
setreuid()
をサポートしているマシンでのみ swap できる。
$(
: プロセスの実 gid。
同時に複数のグループに属することをサポートするマシンでは、
スペースで区切られたユーザが属しているグループのリストとなる。
最初のものは getgid()
で得られるものである。
残りは getgroups()
で得られるものであり、
その内の一つは最初のものと同じかも知れない。
覚え方:
parentheses are used to GROUP things.
The real gid is the group you LEFT, if you're running setgid.
$)
: プロセスの実効 gid。
同時に複数のグループに属することをサポートするマシンでは、
スペースで区切られたユーザが属しているグループのリストとなる。
最初のものは getegid()
で得られるものである。
残りは getgroups()
で得られるものであり、
その内の一つは最初のものと同じかも知れない。
覚え方:
parentheses are used to GROUP things.
The effective gid is the group that's RIGHT for you,
if you're running setgid.
(注意)
$<
、$>
、$(
、
$)
は対応する set[re][ug]id()
ルーチンをサポートするマシンでのみ
セットされる。
$(
と $)
は、
setregid()
をサポートするマシンでのみ swap できる。
$:
: format で文字列を分ける際の直前の文字列セット
format
において、文字列が分けられて継続フィールド
(^
で始まる)に入る時のその直前の文字セット。
デフォルトは \n-
で、
文字列はホワイトスペース又はハイフンの後で分けられる。
覚え方:
a "colon" in poetry is a part of a line.
$^D
: 現在のデバッグフラグの値。
覚え方:
-D
スイッチの値。
$^F
: システムファイルディスクリプタの最大値で、通常 2。
システムファイルディスクリプタは子プロセスに渡されるが、
それより値が大きいファイルディスクリプタは渡されない。
open
の際には、
たとえ open
が失敗してもシステムファイルディスクリプタは保存される。
通常のファイルディスクリプタは open
を試みる前に close
される。
覚え方:
-D
スイッチの値。
$^I
: ファイルをその場で変更する場合の拡張子の値。
その場で変更するのを禁止するには、これを undef する。
覚え方:
-i
スイッチの値。
$^P
: デバッガが自分自身をデバッグしないためにクリアする内部フラグ。
これをクリアすることで 自分自身をデバッグすることを不可能にすることが考えられる。
$^T
: スクリプトの実行が始まった時刻(epoch からの秒数)。
ファイルテスト -M
,-A
,-C
で返る値はこの値に基づいている。
$^W
: 現在の警告スイッチの値。
覚え方:
-w
スイッチに関連した値。
$^X
: Perl そのものが起動された際の名前。argv[0]
から得る。
$ARGV
: <>
から読み込んでいる時、カレントファイル名が入っている。
@ARGV
: スクリプトに与えられたコマンドライン引数。
$#ARGV
は通常 引数の数 - 1 になっていることに注意。
なぜなら、$ARGV[0]
は最初の引数であって、
コマンドの名前ではないからだ。
コマンド名を知るには $0
を見よ。
See $0.
@INC
: perl スクリプトを探す場所のリスト
do EXPR
コマンドまたは require
コマンドで評価される。
最初は コマンドスイッチ -I
で指定した引数 + デフォルト perl ライブラリ
(多分 /usr/local/lib/perl
、
次に .
すなわちカレントディレクトリ )が入っている。
%INC
: インクルードしたファイルの位置
連想配列 INC
には do
または require
を用いて
インクルードされたファイル名が入っている。
key
は指定したファイル名、
value
はファイルが実際に見つかった場所である。
require
コマンドはこの配列を用いて
指定したファイルが既にインクルードされたかどうかを決定する。
%ENV
: 現在の環境。
ENV
の値を変更すると、子プロセスの環境も変わる。
%SIG
: さまざまな signal に対応するハンドラをセットする。
(例)
sub handler { # 1st argument is signal name local($sig) = @_; print "Caught a SIG$sig--shutting down\n"; close(LOG); exit(0); } $SIG{'INT'} = 'handler'; $SIG{'QUIT'} = 'handler'; ... $SIG{'INT'} = 'DEFAULT'; # デフォルトのアクションに戻す $SIG{'QUIT'} = 'IGNORE'; # SIGQUIT を無視する
配列 SIG
は perl スクリプトでセットされた signal に対応する値しか
含まない。
perl においてはパッケージ間で変数が干渉しあわないようにするため、
別々の名前空間を用意している。デフォルトでは、
perl スクリプトは main
というパッケージにコンパイルされる。
package
宣言を使うと、名前空間を変えることができる。
パッケージ宣言の効く範囲は、宣言から閉じたブロックの最後までである
(local()
宣言子と同じ)。
通常、パッケージ宣言は require
でインクルードされるファイルの
最初の宣言として使う。
一箇所以上でパッケージを使うことができる。 それは単にブロックの残りに対してコンパイラが使う シンボルテーブルが変わるだけである。
識別子にパッケージ名と '
(シングルクォート)をつけることで、
他のパッケージの変数やファイルハンドルを参照することができる。
パッケージ名がなければ、main
が使われる。
アルファベットで始まる識別子のみパッケージのシンボルテーブルに格納される。
他のシンボルは main
パッケージに格納される。
さらに、識別子 STDIN
、STDOUT
、STDERR
、ARGV
、
ARGVOUT
、ENV
、INC
、SIG
は
それ本来の目的以外に使う場合でもパッケージ main
のままである。
また、m
、s
、y
という名前のパッケージを使うと、
パッケージ名をつけた識別子を使うことはできない。
なぜなら、それぞれパターンマッチ、置換、変換 を表すと解釈されるからである。
eval
される文字列は eval
と同じパッケージにコンパイルされる。
(ただし、$SIG{}
への代入においては、
シグナルハンドラは main
パッケージにあると仮定される。
パッケージ内にシグナルハンドラを作りたい場合は
シグナルハンドラ名にパッケージ名をつけること。)
例としては、perl ライブラリにある perldb.pl
がある。
これは、デバッガがデバッグしようとするスクリプト内の変数を干渉しないように、
最初に DB
パッケージに入る。
そして、いろいろな場合に、
main
パッケージの文脈で expression を評価するために
一時的に main
パッケージに切り変わる。
パッケージのシンボルテーブルは
パッケージ名の前に _
をつけた名前の連想配列に格納されている。
連想配列の各エントリの値は、
*name
記法を使う際に参照される値と同じである。
実際、次の例は同じ効果がある(もちろん main
パッケージにおいて)が、
一つ目の方が、コンパイル時にシンボルテーブルを探すので、より効率がよい。
local(*foo) = *bar; local($_main{'foo'}) = $_main{'bar'};
これを使って例えばパッケージ内の全変数を出力することができる。
以下に perl ライブラリから dumpvar.pl
を示す。
package dumpvar; sub main'dumpvar { ($package) = @_; local(*stab) = eval("*_$package"); while (($key,$val) = each(%stab)) { { local(*entry) = $val; if (defined $entry) { print "\$$key = '$entry'\n"; } if (defined @entry) { print "\@$key = (\n"; foreach $num ($[ .. $#entry) { print " $num\t'",$entry[$num],"'\n"; } print ")\n"; } if ($key ne "_$package" && defined %entry) { print "\%$key = (\n"; foreach $key (sort keys(%entry)) { print " $key\t'",$entry{$key},"'\n"; } print ")\n"; } } } }
このサブルーチンは dumpvar
パッケージ内にコンパイルされるが、
main
パッケージにおいてサブルーチン名を使用可能とするために、
サブルーチン名の前にパッケージ名をつけなければならないことに注意。
プログラマには皆、当然ながら、体裁に関して自分自身の好みがあるが、 プログラムを読み易くするための一般的なガイドラインがいくつかある。
perl はどんなことをする場合でも複数の方法があるように設計されているので、 もっとも読み易い方法を選ぶのがよい。たとえば、
open(FOO,$foo) || die "Can't open $foo: $!";
は次よりもよい。
die "Can't open $foo: $!" unless open(FOO,$foo);
なぜなら、後者は文のメインポイントを修飾子として隠しているからである。
一方、
print "Starting analysis\n" if $verbose;
は次よりもよい。
$verbose && print "Starting analysis\n";
なぜなら、
メインポイントはユーザが -v
をタイプしたかどうかではないからだ。
同様に、演算子がデフォルトの引数を仮定しているからといって、 それはデフォルトを用いなければならないということではない。 デフォルトはちょっとしたプログラムを書く 怠け者のシステムプログラマのためにある。 プログラムを読み易くしたければ、引数を書いた方がよい。
上と同じようなことだが、 あちこちで括弧を省略することができるということは次のように書け、 ということではない。
return print reverse sort num values array; return print(reverse(sort num (values(%array))));
あやふやな時は、括弧をつけよう。
少なくとも、物好きが、vi
で %
キーを押すかもしれない。(?)
When in doubt, parenthesize. At the very least it will let some poor schmuck bounce on the % key in vi.
あやふやでない時でも、 君の後を継いでコードのメンテナンスをしなければならない人物の 精神福利を考えよう。彼はおそらく誤った所に括弧をつけるだろう。
perl は真ん中から抜けられるように last
宣言子を用意している。
見易くするため、インデントを少し少なくしよう。
line: for (;;) { statements; last line if $foo; next line if /^#/; statements; }
loop
ラベルを使え --
ラベルは多重ループから抜けるためだけでなく、
より読み易くするためにある。
一つ前の例を見よ。
eval
構造の中でそれが失敗するかどうかテストせよ。
ある機能が
どのバージョン、どのパッチレベルでインプリメントされたかが分かっているなら、
$]
を使ってその機能があるかどうかを調べることができる。
perl を -d
オプションをつけて起動すると、
デバッグモニタのもとでスクリプトが実行される。
デバッガは最初の実行可能文の前で止まり、以下に示すコマンドを入力するよう促す。
h
T
s
n
Next
. 次の文の始めまで、サブルーチンに入らずに実行する。
f
Finish
. 現在のサブルーチンが終わるまで文を実行する。
c
c line
<CR>
n
または s
を繰り返す。
l min+incr
min
から incr+1
行表示する。
min
を省略すると、最後に表示した次の行から表示する。
incr
を省略すると、最後の incr
の値を用いる。
l min-max
l line
l
-
w line
l subname
l
を使う。
/pattern/
/
はつけなくてもよい。
?pattern?
?
はつけなくてもよい。
L
S
t
b line condition
b subname condition
d line
D
a line command
A
< command
> command
V package
main
パッケージである。
! number
! -number
H -number
q
^D
command
p expr
print DB'OUT expr
と同じ。STDOUT
がリダイレクトされていても、
ファイルハンドルDB'OUT
は /dev/tty
にオープンされている。
デバッガを修正したい場合は、
perl ライブラリから perldb.pl
をコピーし、必要に応じて修正する。
(コマンドラインに -I.
を追加することも必要だろう。)
.perldb
に初期化コードを書くことによってカスタマイズができる。
例えば、次のようにしてエイリアスを定義できる。
$DB'alias{'len'} = 's/^len(.*)/p length($1)/'; $DB'alias{'stop'} = 's/^stop (at|in)/b/'; $DB'alias{'.'} = 's/^\e./p "\e$DB\e'sub(\e$DB\e'line):\et",\e$DB\e'line[\e$DB\e'line]/';
perl は安全な setuid・setgid スクリプトを 安全に書くことができるように設計されている。 シェルは、スクリプトの各行を複数の置換のパスを通して実行するが、 perlはより伝統的な評価法を用いて、 隠れた"わけのわからないもの"を少なくしている。
さらに、perl にはより多くのビルトイン関数があるので、 目的を達するために外部の(そして多分信用できない)プログラムに頼る必要が少ない。
パッチを当てていない 4.2 や 4.3bsd カーネルでは、 setuid スクリプトは危険であると見なされるが、 このカーネルの機能は使用不可にすることができる。
そうしてある場合、perl は setuid・setgid 機構をエミュレートし、同時に、 そうでない場合にはスクリプトについている setuid/gid ビットは 意味のないものであることを知らせる。
カーネルの機能が使用不可になっていない場合、 perl は setuid スクリプトが危険であることを声高に注意する。 カーネルの setuid スクリプト機能を使用不可にするか、 スクリプトに C のラップをかけなくてはならない。
perl が setuid スクリプトを実行する時は、 明らかなトラップにはまらないような予防策を取る。 (幾つかの点で、perl スクリプトは同じ内容の C プログラムよりも安全である。)
コマンドライン引数、環境変数、入力はすべて"汚れている"と見なされ、 サブシェルを起動するコマンドや、 ファイル・ディレクトリ・プロセスを変更するコマンドには、 直接的であれ間接的であれ、使用が許されない。
過去に"汚れた"値を参照した expression でセットされた変数もまた "汚れる"("汚れた"値が変数に影響を及ぼすことが論理的に不可能であっても)。
例えば:
$foo = shift; # $foo は汚れている $bar = $foo,'bar'; # $bar もまた汚れる $xxx = <>; # 汚れている $path = $ENV{'PATH'}; # 汚れているが、下を見よ $abc = 'abc'; # 汚れていない system "echo $foo"; # 危険 system "/bin/echo", $foo;# 安全(sh は使わない) system "echo $bar"; # 危険 system "echo $abc"; # PATH がセットされないかぎり危険 $ENV{'PATH'} = '/bin:/usr/bin'; $ENV{'IFS'} = '' if $ENV{'IFS'} ne ''; $path = $ENV{'PATH'}; # 汚れていない system "echo $abc"; # 今度は安全! open(FOO,"$foo"); # OK open(FOO,">$foo"); # OK ではない open(FOO,"echo $foo|"); # OK ではないが... open(FOO,"-|") || exec 'echo', $foo; # OK $zzz = `echo $foo`; # 危険、zzz は汚れる unlink $abc,$foo; # 危険 umask $foo; # 危険 exec "echo $foo"; # 危険 exec "echo", $foo; # 安全(sh は使わない) exec "sh", '-c', $foo; # 安全とみなされる、ああ
"汚れ"は全スカラー値と結合しており、 配列の幾つかの要素は"汚れて"いても他の要素は大丈夫、ということも可能である。
何か危険なことをしようとすると、
Insecure dependency
または Insecure PATH
というメッセージと共に
致命的なエラーとなる。
それでも危険なシステムコールや exec
を書くことはできるが、
それは上の最後の例のような明らかな場合のみであることに注意。
また、"汚れ"機構をサブパターンを参照することで回避することもできる。
perl は $1
、$2
などを使ってサブストリングを参照する場合には
パターンを書いた人が何をやっているのかを知っているものだと仮定している。
$ARGV[0] =~ /^-P(\w+)$/; $printer = $1; # 汚れていない
\w+
はシェルのメタキャラクタにマッチしないので、
これはかなり安全である。
.+
を使っていたら危険であっただろうが、perl はそれをチェックしないので、
パターンには注意するべきである。
これは、ファイル操作を行う場合にユーザが与えるファイル名を"汚さない"ための
唯一の機構である。
($>
を $<
と同じにしないかぎり。)
"汚れた"値を気にかけない他の操作においてもトラブルを起こし得る。
ユーザが与えるファイル名を使ってファイルテストをする場合には、
よく考えるように。
可能ならば、 $> = $<
とした後で open
などを行った方がいい。
perl は"汚れた"名前のファイルを読み込みのために open
することを許す。
したがって、出力する内容には注意すること。
See $right for $>
, and See $left for $<
.
"汚れ"機構は馬鹿げた間違いを防ぐために作ったもので、 何も考えなくてもよいようにするためのものではない。
perl はサブプロセスを実行する際および -S
を用いた場合
スクリプトを探す際に PATH
を使用する。
chdir
を引数なしで使う場合、HOME
または LOGDIR
を用いる。
これら以外では、 実行時にスクリプトおよび子プロセスから環境変数を使用可能にすることを除いて、 perl は環境変数を用いない。 しかし、setuid されたスクリプトでは、 用心して何よりも最初に必ず以下の行を実行するのがよいだろう。 これはユーザに嘘をつかせないためである(just to keep people honest)。
$ENV{'PATH'} = '/bin:/usr/bin'; # or whatever you need $ENV{'SHELL'} = '/bin/sh' if $ENV{'SHELL'} ne ´´; $ENV{'IFS'} = ´´if $ENV{'IFS'} ne ´´;
Larry Wall <lwall@netlabs.com>
MS-DOS サポートは Diomidis Spinellis <dds@cc.ic.ac.uk>
-e
オプションをつけた時に使用するテンポラリファイル
/tmp/perl-eXXXXXX
コンパイルエラーはエラーの起こった行番号に加えて、
次に解析されるはずだったトークンまたはトークンの種類を教えてくれる。
(-e
オプションを通して perl に渡されるスクリプトの場合は、
各々の -e
が 1 行と数えられる。)
さらに Setuid スクリプトの場合には、
Insecure dependency
のようなエラーメッセージを起こす場合がある。
Setuid scripts の項を参照。See Setuid scripts.
if
や while
を使う時には { }
が必要である。
$
か @
で始まる。
$[
をセットしないかぎり配列添え字は 0 から始まる。
substr()
や index()
における文字位置も同様である。
split
してくれない。
自分で split
して配列に格納する必要がある。
そして、split
関数は異なる引数をとる。
$0
ではなく通常 $_
に入っている。
普通、改行は取り除かれていない。
($0
は実行しているプログラムの名前である。)
$数字
は入力行のフィールドを参照しない --
最後のパターンマッチでマッチした各文字列を参照する。
$,
、$\
をセットしないかぎり、
print
はフィールドセパレータ、レコードセパレータを出力しない。
..
であり、コンマではない。
(コンマは C と同じように働く。)
=~
であり、~
ではない。
(~
は、C と同じく、補数を表す。)
**
であり、^
ではない。
(^
は、C と同じく、XOR
演算子である。)
.
であり、ヌル文字列ではない。
(ヌル文字列を使ったなら、/pat/ /pat/
が解析不能になるだろう。
なぜなら、3 つめのスラッシュは除算演算子と解釈されるからである。--
トークン解釈は実際の所、
/
や ?
や <
といった演算子については
少しコンテキストに敏感である。
そして、実は、 .
それ自体は数字の最初にもなりうるのである。)
next
、exit
、continue
の働きが違う。
awk perl ARGC $#ARGV ARGV[0] $0 FILENAME $ARGV FNR $. - something FS (何でもよい) NF $#Fld, or some such NR $. OFMT $# OFS $, ORS $\ RLENGTH length($&) RS $/ RSTART length($`) SUBSEP $;
a2p
にかけて、
その出力を見るとよい。
if
や while
を使う時には { }
が必要である。
else if
の代わりに elsif
を使う。
break
、continue
はそれぞれ last
、next
となる。
switch
文はない。
$
か @
で始まる。
*
をインプリメントしていない。
#
で始まる。 /*
ではない。
ARGV
は大文字でなければならない。
link
、unlink
、rename
などの"システム"コールは
成功すれば非 0 を返す。0 ではない。
\
ではなく $
を使う。
(
、)
、|
の前には
バックスラッシュをつけない。
..
であり、コンマではない。
(コンマは C と同じように働く。)
``
演算子においては、
コマンドを ''
で括らなければ変数置換が行われる。
``
演算子は、csh
と異なり、返り値をそのまま返す。
csh
)は各コマンド行について複数レベルの置換を行う。
perl は ""
、``
、<>
、検索パターンなど、
特定の構造について置換を行う。
@ARGV
を通して利用可能である。
$1
、$2
などではない。
Perl の本、Programming Perl では 次の項目を省略あるいは入れ損なっている。
eval "/usr/bin/perlは以下が正しい。
eval "exec /usr/bin/perl
sum
に相当するプログラムは、
極めて小さいファイルでしか動作しない。
大きなファイルで用いるには、以下のようにする。
undef $/; $checksum = unpack("%32C*",<>) % 32767;
alarm
と sleep
の記述が
シグナル SIGALARM
に言及しているが、
これらは SIGALRM
でなければならない。
$/
に初期値をセットする -0
スイッチが Perl に追加された。
-l
スイッチが自動的な行末処理を行なうようになった。
qx//
構造は ``
と同義になった。
$0
に代入を行なうことが可能になった。
@###.##
が偶然省略された。
s///ee
が評価を複数回行うことがわかっていなかった。
これは仕様と解釈するべきである。
(LIST) x $count
が配列の繰り返しを行なうようになった。
""
内において、エスケープが追加された:\e
,\a
,\x1b
,\c[
,\l
,\L
,\u
,\U
,\E
.$/
は複数文字のデリミッタとしてセットすることができるようになった。
g
修飾子がもうけられた。
これにより一つの文字列に対し複数のマッチ検索を繰り返すことが可能になった。
FILEHANDLE
に対するデフォルトのページ先頭フォーマットは
FILEHANDLE_TOP
であって top
ではない。
eval {}
と sort {}
構造がバージョン 4.011 で追加された。
perl は型キャスティング、atof()
、sprintf()
などの
さまざまな操作について、あなたのマシンの定義を使っている。
stdio
があるストリームの read
と write
の間に、
seek
または eof
を必要としているなら perl もそうなる。
(これは sysread()
および syswrite()
にはあてはまらない。)
どのデータタイプにも決まったサイズの上限はないが(メモリサイズは別)、 それでもいくつかの限界がある。
-S
を使う場合、
PATH
のどの要素も 255 文字を超えてはならない。
perl は実際の所は、Pathologically Eclectic Rubbish Lister
(病理学的折衷主義くずリスター)の略であるが、
私がそう言ったということはだれにも言わないでほしい。
!~
: Specify string to be operated
&
: Subroutines
()
: Null list
**
: Exponentiation
**=
: Exponentiation
++
: Misc( Operators )
--
: Misc( Operators )
-A
: File test operators
-B
: File test operators
-b
: File test operators
-C
: File test operators
-c
: File test operators
-d
: File test operators
-e
: File test operators
-f
: File test operators
-g
: File test operators
-k
: File test operators
-l
: File test operators
-M
: File test operators
-O
: File test operators
-o
: File test operators
-p
: File test operators
-R
: File test operators
-r
: File test operators
-S
: File test operators
-s
: File test operators
-T
: File test operators
-t
: File test operators
-u
: File test operators
-W
: File test operators
-w
: File test operators
-X
: File test operators
-x
: File test operators
-z
: File test operators
.
: Concatenation
..
: Repeat & Range
.=
: Concatenation
/PATTERN/
: m/PATTERN/
<=>
: Comparison
=~
: Specify string to be operated
?PATTERN?
: ?PATTERN?
accept
: Networking
alarm
: alarm
atan2
: Arithmetic functions
bind
: Networking
binmode
: binmode
caller
: caller
chdir
: chdir
chmod
: chmod
chop
: chop
chown
: chown
chroot
: chroot
close
: close
closedir
: Directory reading
cmp
: Comparison
connect
: Networking
continue
: Compound statements
cos
: Arithmetic functions
crypt
: crypt
dbmclose
: dbmclose
dbmopen
: dbmopen
defined
: defined
delete
: delete
die
: die
do
: do
dump
: dump
each
: each
else
: Compound statements
elsif
: Compound statements
endgrent
: Info from system files
endhostent
: Info from system files
endnetent
: Info from system files
endprotoent
: Info from system files
endpwent
: Info from system files
endservent
: Info from system files
eof
: eof
eq
: Comparison
eval
: eval
exec
: exec
exit
: exit
exp
: Arithmetic functions
fcntl
: fcntl
fileno
: fileno
flock
: flock
for
: Compound statements
foreach
: Compound statements
fork
: fork
ge
: Comparison
getc
: getc
getgrent
: Info from system files
getgrgid
: Info from system files
getgrnam
: Info from system files
gethostbyaddr
: Info from system files
gethostbyname
: Info from system files
gethostent
: Info from system files
getlogin
: getlogin
getnetbyaddr
: Info from system files
getnetbyname
: Info from system files
getnetent
: Info from system files
getpeername
: Networking
getpgrp
: getpgrp
getppid
: getppid
getpriority
: getpriority
getprotobyname
: Info from system files
getprotobynumber
: Info from system files
getprotoent
: Info from system files
getpwent
: Info from system files
getpwnam
: Info from system files
getpwuid
: Info from system files
getservbyname
: Info from system files
getservbyport
: Info from system files
getservent
: Info from system files
getsockname
: Networking
getsockopt
: Networking
gmtime
: Conversion functions
goto
: goto
grep
: grep
gt
: Comparison
hex
: Conversion functions
if
: Compound statements
index
: index
int
: Arithmetic functions
ioctl
: ioctl
join
: join
keys
: keys
kill
: kill
last
: last
le
: Comparison
length
: length
link
: link
listen
: Networking
local
: local
localtime
: Conversion functions
log
: Arithmetic functions
lstat
: lstat
lt
: Comparison
m
: m/PATTERN/
mkdir
: mkdir
msgctl
: System V IPC functions
msgget
: System V IPC functions
msgrcv
: System V IPC functions
msgsnd
: System V IPC functions
ne
: Comparison
next
: next
oct
: Conversion functions
open
: open
opendir
: Directory reading
ord
: Conversion functions
pack
: pack
picture
: Formats
pipe
: pipe
pop
: pop
print
: print
printf
: printf
push
: push
q
: q
qq
: q
qx
: q
rand
: Arithmetic functions
read
: read
readdir
: Directory reading
readlink
: readlink
recv
: Networking
redo
: redo
rename
: rename
require
: require
reset
: reset
return
: return
reverse
: reverse
rewinddir
: Directory reading
rindex
: rindex
rmdir
: rmdir
s
: s/PATTERN/REPLACEMENT/
scalar
: scalar
seek
: seek
seekdir
: Directory reading
select
: select
semctl
: System V IPC functions
semget
: System V IPC functions
semop
: System V IPC functions
send
: Networking
setgrent
: Info from system files
sethostent
: Info from system files
setnetent
: Info from system files
setpgrp
: setpgrp
setpriority
: setpriority
setprotoent
: Info from system files
setpwent
: Info from system files
setservent
: Info from system files
setsockopt
: Networking
shift
: shift
shmctl
: System V IPC functions
shmget
: System V IPC functions
shmread
: System V IPC functions
shmwrite
: System V IPC functions
shutdown
: Networking
sin
: Arithmetic functions
sleep
: sleep
socket
: Networking
socketpair
: Networking
sort
: sort
splice
: splice
split
: split
sprintf
: sprintf
sqrt
: Arithmetic functions
srand
: Arithmetic functions
stat
: stat
study
: study
substr
: substr
symlink
: symlink
syscall
: syscall
sysread
: sysread
system
: system
syswrite
: syswrite
tell
: tell
telldir
: Directory reading
time
: Arithmetic functions
times
: times
tr
: tr/SEARCHLIST/REPLACEMENTLIST/
truncate
: truncate
umask
: umask
undef
: undef
unlink
: unlink
unpack
: unpack
unshift
: unshift
utime
: utime
values
: values
vec
: Conversion functions
wait
: wait
waitpid
: waitpid
warn
: warn
while
: Compound statements
write
: write
x
: Repeat & Range
x=
: Repeat & Range
y
: tr/SEARCHLIST/REPLACEMENTLIST/
-0
: レコードセパレータの指定
-a
: オートスプリットモード
-c
: 文法チェック
-d
: デバッグモード
-D
: デバッグフラグをセットする
-e
: コマンドラインからスクリプトを入力
-i
: 入力ファイルを修正し、バックアップファイルを作成する
-I
: C プリプロセッサにインクルードファイルの位置を知らせる
-l
: 行末処理を自動的に行なう
-n
: sed -n や awk のエミュレート
-p
: sed のエミュレート
-P
: コンパイル前に C プリプロセッサを通す
-s
: コマンドラインオプションの解析結果を変数にセットする
-S
: スクリプトを環境変数 PATH
を用いて探す
-u
: スクリプトのコンパイル後、コアダンプする
-U
: 安全でない操作を可能にする
-v
: perl のバージョンとパッチレベルを表示する
-w
: 識別子に関するさまざまな警告を出す
-x
: スクリプトがメッセージ内に埋め込まれていることを知らせる