日本語 perl texinfo について
*********************

日本語 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 とは何か?
**********

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 は次の順序でスクリプトを探す。

 1. コマンドラインの -e スイッチで 1 行ずつ指定するスクリプト。

 2. コマンドラインの最初のファイル名で指定されるファイルに含まれるスクリプト。 (#! 指定をサポートするシステムにおいては、この方法でインタプリタが起動される)

 3. 暗黙的に標準入力から渡されるスクリプト。これは引数にファイル名が一つもない場合だけである。標準入力のスクリプトに引数を渡すには、スクリプト名として明示的に - を指定しなければならない。

スクリプトが見つかると、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進数

行末処理を自動的に行う。二つの効果がある:

 1. -n または -p と一緒に用いた場合、行ターミネータを自動的に除く。

 2. $\ に 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

識別子について以下の場合に警告を出す。

  * 一度だけ出てくるもの

  * セットする前に使用されるスカラー変数

  * 複数回定義されるサブルーチン

  * 定義されていないファイルハンドルへの参照

  * リードオンリーでオープンしたファイルハンドルへの書き込み

  * == を数値ではなさそうな値に用いている

  * サブルーチンの再帰が 100 以上

-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.

演算子 & 関数
********

指数
==

**
     指数演算子。

**=
     指数演算 & 代入演算子。

ヌルリスト
=====

()
     配列を初期化するために使う、ヌルリスト。

文字列結合
=====

.
     2 つの文字列の結合演算子。

.=
     結合 & 代入演算子。

比較演算子
=====

eq
     文字列の同値性( == は数値の同値性)。 (もし、状況に応じて == が文字列および数値の両方の同値性を表す awk に慣れているなら、注意せよ!)

ne
     文字列の非同値性( != は数値の非同値性)。

lt
     文字列の less than 。

gt
     文字列の greater than 。

le
     文字列の less than or equal 。

ge
     文字列の greater than or equal 。

cmp
     文字列の比較。-1、0、または 1 を返す。

<=>
     数値の比較。-1、0、または 1 を返す。

操作対象文字列の指定
==========

=~
     演算には、検索・変更をデフォルトで文字列 $_ に対して行うものがある。 =~ 演算子を用いると、別の文字列に対してその演算が行われる。右の引数は検索パターン・置換・変換(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
--

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
----

goto LABEL

     LABEL というラベル宣言を検索し、そこから実行を再開する。現在は do {} 構造の中を除くプログラムの本体内のラベルにしか goto できない。 goto はあまり効率的にはインプリメントされておらず、 sed-to-perl 変換を容易にしているだけである。私がいつ、 sed スクリプトのサポートは残したままこのセマンティクスを変更するかわからない。使いたければ自らの責任で使うこと。全く使わないのが一番良い。

last
----

last LABEL
last

     last コマンドは C での break(ループ中で使用される) と似ている。現在実行中のループから直ちに抜け出す。 LABEL を省略すると、最も奥のループを構成する囲みの最後にとぶ。 continue がもしあっても、実行されない。

          line: while (<STDIN>) {
               last line if /^$/;  # ヘッダーが終わったら抜ける
               ...
          }

next
----

next LABEL
next

     next コマンドは C における continue に似ていて、ループの次の繰り返しを行う。

          line: while (<STDIN>) {
               next line if /^#/;  # コメントは捨てる
               ...
          }

     注意:

     もし continue ブロックが上例にあれば、無視される行であっても実行される。LABEL を省略した場合、 next は括弧で囲まれたループの最後にとぶ。

redo
----

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
------

return LIST

     指定した値でサブルーチンから返る。

     注意:

     サブルーチンからは、最後に評価した expression の値で自動的に返る。それがお勧めである --- return を明示すると、若干遅くなる。

数学関数
====

atan2
-----

atan2(X,Y)

Y/X の arctangent を -π から π までの範囲で返す。

cos
---

cos(EXPR)
cos EXPR

EXPR はラジアン。省略すると $_ を使う。

sin
---

sin(EXPR)
sin EXPR

EXPR (ラジアン) のサインを返す。 EXPR を省略すると、$_ のサインを返す。

exp
---

exp(EXPR)
exp EXPR

e の EXPR 乗を返す。 EXPR を省略すると、exp($_) を返す。

sqrt
----

sqrt(EXPR)
sqrt EXPR

EXPR のルート(2 乗根)を返す。 EXPR を省略すると、$_ のルートを返す。

int
---

int(EXPR)
int EXPR

EXPR を整数に変換した値を返す。 EXPR を省略すると、$_ を使用する。

log
---

log(EXPR)
log EXPR

EXPR の(基 e の)log を返す。 EXPR を省略すると、$_ の log を返す。

rand
----

rand(EXPR)
rand EXPR
rand

0 から EXPR の間のランダムな小数点の数値を返す (EXPR は正でなくてはならない)。 EXPR を省略すると、0 と 1 の間の値を返す。srand() も参照。

srand
-----

srand(EXPR)
srand EXPR

rand 演算子で用いる乱数の seed をセットする。 EXPR を省略すると、srand(time) を実行する。

time
----

time

1970 年 1 月 1 日 0 時 0 分 0 秒(UTC)からの秒数を返す。

gmtime() や localtime() に指定することができる。

See gmtime, and see localtime.

変換関数
====

gmtime
------

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
---------

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
---

hex(EXPR)
hex EXPR

EXPR を 16 進文字列であると見なして 10 進値を返す (0 または 0x で始まる文字列の変換については oct() を参照。)。 EXPR を省略すると、$_ を使用する。

oct
---

oct(EXPR)
oct EXPR

EXPR の値を 8 進文字列であると解釈してその 10 進値を返す。 (EXPR が 0x で始まる場合は代わりに 16 進文字列であると解釈する。) 次の例では、標準的な記述による 10、8、16 進を扱うことができる。

     $val = oct($val) if $val =~ /^0/;

EXPR を省略した場合、 $_ を使用する。

ord
---

ord(EXPR)
ord EXPR

EXPR の最初の文字の ascii value を数値で返す。 EXPR を省略すると、$_ を使用する。

vec
---

vec(EXPR,OFFSET,BITS)

文字列を unsigned integer のベクトルとして扱い、指定した bitfield の値を返す。代入もできる。BITS は 2 の 1 乗から 32 乗まででなければならない。

vec() が返すベクトルは論理演算子 |、&、^ を用いて操作できる。両オペランドが文字列の場合はビットベクトル演算であると仮定する。この解釈はプログラムに少なくとも一つの vec() がないとなされない。 (古いプログラムを守るため)

ビットベクトルを文字列や 0 と 1 の配列に変換するには、次のようにすればよい。

     $bits = unpack("b*", $vector);
     @bits = split(//, unpack("b*", $vector));

正確なビット長がわかっているなら、 * の代わりにそれを使うことができる。

データ構造変換関数
=========

pack
----

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
------

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
----

chop(LIST)
chop(VARIABLE)
chop VARIABLE
chop

     文字列の最後の文字を落としてその文字列を返す。入力文字列から最後の改行文字を除くのに使ったりする。文字列を省略した場合、$_ を使う。

          while (<>) {
               chop;     # 最後の \n を取る
               @array = split(/:/);
               ...

     左辺値であれば引数は何でもいい。

          chop($cwd = `pwd`);
          chop($answer = <STDIN>);

     リストを chop した場合は、全リストを chop し、最後に chop した文字を返す。

crypt
-----

crypt(PLAINTEXT,SALT)

     文字列を C ライブラリの crypt() と全く同じように encrypt する。パスワードファイル中のくだらないパスワードをチェックするのに便利である。白い帽子を被った奴だけがこれをするべきだ。(?) (Only the guys wearing white hats should do this.)

eval
----

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
-----

index(STR,SUBSTR,POSITION)
index(STR,SUBSTR)

     STR 内で SUBSTR が POSITION 文字目またはそれ以降に最初に現れる位置を返す。

     POSITION を省略した場合は文字列の最初から検索する。返り値のベースは 0 または $[ にセットされていればその値である。 SUBSTR が見つからなければ、ベースから 1 を引いた値を返す。通常 -1 である。

     See $[.

length
------

length(EXPR)
length EXPR

     EXPR の値の文字列長を返す。 EXPR を省略すると、$_ の長さを返す。

rindex
------

rindex(STR,SUBSTR,POSISION)
rindex(STR,SUBSTR)

     index と同じような動作をするが、違いは STR 内に最後に現れる SUBSTR の位置を返すことである。

     POSITION を指定すると、その位置またはそれより前で最後に現れる位置を返す。 See index.

substr
------

substr(EXPR,OFFSET,LEN)
substr(EXPR,OFFSET)

     EXPR から文字列を取り出し返す。1 文字目はオフセット 0 であるが、 $[ にセットすることで変えることができる。OFFSET が負の場合は、文字列の終わりからその数分戻った所から始める。

     LEN を省略すると、文字列の残り全部を返す。

     substr() 関数は左辺値として使うこともできるが、この場合 EXPR が 左辺値でなくてはならない。 LEN よりも短いものを代入すると、その文字列は短くなり、 LEN よりも長いものを代入するとそれに合わせて長くなる。文字列の長さを変えない場合は sprintf を用いてパディングまたは切捨てをしなければならない。

     See $[.

配列 & リストを扱う関数
=============

delete
------

delete $ASSOC{KEY}

     指定した連想配列から、指定した値を削除する。削除された値を返すか、何も削除されなかった場合は undefined value を返す。 dbm ファイルに bind された連想配列を削除すると、 dbm ファイルのエントリを削除する。

     以下の例では連想配列の全ての値を削除する。

          foreach $key (keys %ARRAY) {
               delete $ARRAY{$key};
          }

     (が、reset コマンドを使った方が速いだろう。 undef %ARRAY はもっと速いだろう。)

each
----

each(ASSOC_ARRAY)
each ASSOC_ARRAY

     連想配列の、キーと次の値への値?からなる 2 要素の配列を返す。

     従って、繰り返しができる。エントリーはランダムな順序で返ってくる。

     全配列を読み終えると、ヌル配列が返る(これは代入された場合は FALSE すなわち 0 になる)。この後続けてコールすると繰り返しを再び始める。繰り返し情報は全ての配列を読むことによってのみ初期化される。

     繰り返しの途中では配列を変更してはいけない。繰り返し情報は各連想配列に一つずつあり、プログラム中の全ての each(), key(), values() 関数コールで共有される。次の例では printenv のように環境をプリントアウトするが、順番が異なる。

          while (($key,$value) = each %ENV) {
               print "$key=$value\n";
          }

     See keys, and see values.

grep
----

grep(EXPR,LIST)

     LIST の全要素について EXPR を評価し (各要素を $_ にセットしながら)、 expression が true であると評価された要素からなる配列を返す。

     スカラーのコンテキストでは、expression が true となった回数を返す。

          @foo = grep(!/^#/, @bar);    # コメントを無視する

     注意: $_ は配列値への参照となっているので、配列要素を変更するのに用いることができる。これは便利である一方、 LIST が名前のついた配列でない場合には、ちょっと変な結果を返すことがある。

join
----

join(EXPR,LIST)
join(EXPR,ARRAY)

     LIST または ARRAY の個々の文字列を EXPR の値で区切った一つの文字列にする。

          $_ = join(':',$login,$passwd,$uid,$gid,$gcos,$home,$shell);

     See split.

keys
----

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";
          }

     See each, and see values.

pop
---

pop(ARRAY)
pop ARRAY

     配列の最後の値を返し、配列を 1 減らす。

          $tmp = $ARRAY[$#ARRAY--];

     と同じ効果がある。配列に要素が一つもない場合は undefined value を返す。

     See push.

push
----

push(ARRAY,LIST)

     ARRAY(@ は付けなくてよい)をスタックのように扱い、 LIST の値を ARRAY の最後に追加する。 ARRAY の長さは LIST の長さ分増える。

          for $value (LIST) {
               $ARRAY[++$#ARRAY] = $value;
          }

     と同じ効果を持つが、より効率がよい。

     See pop.

reverse
-------

reverse(LIST)
reverse LIST

     配列のコンテキストでは、LIST の要素を逆順にした配列値を返す。

     スカラーのコンテキストでは、 LIST の最初の要素のバイト列を逆にした文字列を返す。

shift
-----

shift(ARRAY)
shift ARRAY
shift

     配列の最初の値を取り出してそれを返す。そして、配列の長さを 1 減らして全要素をずらす。配列に要素がない場合、undefined value を返す。

     ARRAY を省略すると、メインプログラムでは @ARGV を shift し、サブルーチンでは @_ を shift する。 (これは lexically(?) に決定される。)

     unshift()、push()、pop() も参照のこと。 shift() と unshift() は、 push() と pop() が配列の右について行うのと同じことを配列の左について行う。

     See unshift, see push, and see pop.

sort
----

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
------

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
-----

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 も参照のこと。

     See chop, and see join.

unshift
-------

unshift(ARRAY,LIST)

     視点により、shift または push の逆を行う。 LIST を ARRAY の前に付け、できた配列の要素数を返す。

          unshift(ARGV, '-e') unless $ARGV[0] =~ /^-/;

     See shift, and see push.

values
------

values(ASSOC_ARRAY)
values ASSOC_ARRAY

     指定した連想配列の全ての値からなる通常の配列を返す。値は全くランダムな順序で返るが、 keys() や each() 関数が同じ配列に対して返すものと同じ順序である。

     See each, and see keys.

ファイル操作関数
========

chmod
-----

chmod(LIST)
chmod LIST

     属性は最初の引数において数値で指定する。属性を変更するのに成功したファイルの数を返す。

          $cnt = chmod 0755, 'foo', 'bar';
          chmod 0755, @executables;

chown
-----

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
----

link(OLDFILE,NEWFILE)

     old filename にリンクされた new filename を作成する。成功なら 1、失敗なら 0 を返す。

lstat
-----

lstat(FILEHANDLE)
lstat FILEHANDLE
lstat(EXPR)
lstat SCALARVARIABLE

     stat() 関数と同じことをするが、シンボリックリンクが指すファイルではなく、シンボリックリンクそのものの stat を返す。シンボリックリンクをインプリメントしていないシステムでは、 stat と同じである。

     See stat.

mkdir
-----

mkdir(FILENAME,MODE)

     FILENAME で指定されるディレクトリを作成する。 permission は MODE(umask で修飾される)で指定する。成功すれば 1 を返し、失敗すれば 0 を返すと共に $! をセットする(errno)。

readlink
--------

readlink(EXPR)
readlink EXPR

     シンボリックリンクがインプリメントされている場合、シンボリックリンクの値を返す。そうでない場合は致命的エラーとなる。システムエラーが起こった場合は undefined value を返し、 $! をセットする(errno)。 EXPR を省略すると、$_ を用いる。

rename
------

rename(OLDNAME,NEWNAME)

     ファイルの名前を変更する。成功すれば 1、そうでなければ 0 を返す。ファイルシステムを超えては働かない。

rmdir
-----

rmdir(FILENAME)
rmdir FILENAME

     FILENAME で指定されたディレクトリが空ならば消去する。成功すれば 1、そうでなければ 0 を返し、$! (errno) をセットする。 FILENAME を省略すると、$_ を用いる。

select
------

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
----

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
-------

symlink(OLDFILE,NEWFILE)

     OLDFILE にシンボリックリンクされた NEWFILE を作成する。成功すれば 1、それ以外では 0 を返す。シンボリックリンクをサポートしないシステムでは、実行時に致命的エラーとなる。それをチェックするには、eval を用いる。

          $symlink_exists = (eval	'symlink("","");', $@ eq '');

truncate
--------

truncate(FILEHANDLE,LENGTH)
truncate(EXPR,LENGTH)

     FILEHANDLE にオープンされたファイルまたは EXPR という名前のファイルを指定する長さに切り詰める。システムに truncate がインプリメントされていなければ致命的エラーとなる。

unlink
------

unlink(LIST)
unlink LIST

     リストされたファイルを消去する。消去に成功したファイルの数を返す。

          $cnt = unlink 'a', 'b', 'c';
          unlink @goners;
          unlink <*.bak>;

     注意: unlink はスーパーユーザであってかつ perl に -U フラグを指定していないかぎりディレクトリは消去しない。これらの条件にあてはまっている場合でも、ディレクトリを unlink することはファイルシステムにダメージを与えることに注意せよ。かわりに rmdir を使うこと。

utime
-----

utime(LIST)
utime LIST

     リストしたファイルの全てについてアクセス時刻と変更時刻を変更する。リストの最初の 2 要素は数値でなくてはならず、アクセス時刻、変更時刻の順である。変更に成功したファイルの数を返す。各ファイルの inode の変更時刻は現在時刻にセットされる。

     touch コマンドの例:

          #!/usr/bin/perl
          $now = time;
          utime $now, $now, @ARGV;

ディレクトリ読み込み関数
============

closedir
--------

closedir(DIRHANDLE)
closedir DIRHANDLE

opendir() で open されたディレクトリを close する。

opendir
-------

opendir(DIRHANDLE,EXPR)

EXPR という名前のディレクトリを open し、 readdir()、telldir()、seekdir()、

rewinddir()、closedir() を可能にする。成功すれば true を返す。

DIRHANDLEs には FILEHANDLEs とは別の名前空間がある。

readdir
-------

readdir(DIRHANDLE)
readdir DIRHANDLE

opendir() でオープンしたディレクトリの次のエントリを返す。配列のコンテキストで用いると、ディレクトリの残りのエントリを全て返す。エントリが残っていない場合は、スカラーのコンテキストでは undefined value、配列のコンテキストではヌルリストを返す。

rewinddir
---------

rewinddir(DIRHANDLE)
rewinddir DIRHANDLE

readdir() で用いる、 DIRHANDLE のカレント位置をディレクトリの最初にセットする。

seekdir
-------

seekdir(DIRHANDLE,POS)

readdir() で用いる DIRHANDLE のカレント位置をセットする。 POS はtelldir() が返す値でなくてはならない。 directory compaction については対応するシステムライブラリ関数と同様の注意が必要である。

telldir
-------

telldir(DIRHANDLE)
telldir DIRHANDLE

DIRHANDLE に対する readdir() の現在の位置を返す。ディレクトリのある位置にアクセスするためにこの値を seekdir() に指定することができる。 directory compaction については対応するシステムライブラリルーチンと同じ注意が必要である。

入出力関数
=====

以下の項目の説明における FILEHANDLE は、 open でオープンされたファイルハンドルか、ファイルハンドルの名前を値に持つスカラー変数である。

binmode
-------

binmode(FILEHANDLE)
binmode FILEHANDLE

     バイナリファイルとテキストファイルを区別する OS において、ファイルをバイナリモードで読むようにする。バイナリモードでない場合は入力の際に CR LF が LF に、出力の際に LF が CR LF に変換される。 Unix の下では何の効果もない。 FILEHANDLE がexpression の場合は、その値がファイルハンドルの名前として解釈される。

close
-----

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
--------

dbmclose(ASSOC_ARRAY)
dbmclose ASSOC_ARRAY

     dbm ファイルと連想配列の bind を終了する。連想配列に残っている値は意味がない。この関数は ndbm がある場合にのみ便利である。

dbmopen
-------

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
---

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
-----

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
------

fileno(FILEHANDLE)
fileno FILEHANDLE

     ファイルハンドルに対するファイルディスクリプタを返す。 select() の bitmap を構築するのに便利である。 FILEHANDLE が expression の場合は、その値がファイルハンドルの名前であると解釈される。

flock
-----

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
----

getc(FILEHANDLE)
getc FILEHANDLE
getc

     FILEHANDLE に結び付いている入力ファイルの次の character を返す。 EOF の場合はヌル文字列を返す。 FILEHANDLE を省略すると、STDIN から読む。

ioctl
-----

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
----

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
----

pipe(READHANDLE,WRITEHANDLE)

     対応するシステムコールと同様、接続されたパイプのペアをオープンする。パイプでつながったプロセスのループは、注意深くやらないとデッドロックを起こすので注意。さらに、perl のパイプは stdio のバッファリングを使うので、アプリケーションによっては、 WRITEHANDLE をコマンド毎にフラッシュするために、 $| をセットする必要があるかもしれない。 See $vline for $|.

     [perl 3.0 パッチレベル 9 以上が必要。]

print
-----

print(FILEHANDLE LIST)
print(LIST)
print FILEHANDLE LIST
print LIST
print

     文字列またはコンマで区切られた文字列のリストを出力する。成功すれば non-zero を返す。 FILEHANDLE はファイルハンドルの名前を値として持つスカラー変数名でもよい。こうすると、1 レベルの間接的な出力ができる。 (注意: FILEHANDLE が変数で、次のトークンが文の終わりの場合はそれが演算子と誤解釈される可能性があるので、間に + を入れるか、引数に括弧をつけるかしなければならない。)

     FILEHANDLE を省略すると、デフォルトでは標準出力(または最後に select された出力チャンネル --- select() 参照 see select.)に出力する。 LIST も省略すると、$_ を STDOUT に出力する。デフォルトの出力チャンネルを STDOUT 以外のものにするには、 select演算子を使用する。

     注意:

     print は LIST を引数に取るので、 LIST の要素は全て配列のコンテキストで評価され、またサブルーチンをコールするとその 1 つ以上の expression は配列のコンテキストで評価される。?

     また、キーワード print の後に左括弧はつけないように注意する必要がある (print への引数を区切る --- + を間に入れるか全引数を括弧で囲む --- ために対応した右括弧をつけたい場合を除いて)。

printf
------

printf(FILEHANDLE LIST)
printf(LIST)
printf FILEHANDLE LIST
printf LIST

     print FILEHANDLE sprintf(LIST) と同等である。

     See print, and see sprintf.

read
----

read(FILEHANDLE,SCALAR,LENGTH,OFFSET)
read(FILEHANDLE,SCALAR,LENGTH)

     指定した FILEHANDLE から、 LENGTH バイトのデータを読んで SCALAR に格納する。実際に読み込んだバイト数、またはエラーがあれば undef を返す。 SCALAR は実際に読んだバイト数に合わせてサイズが変わる。

     OFFSET を指定すると、読んだデータを文字列の先頭ではなく他の場所に格納する。これは実際には、 stdio の fread コールを用いてインプリメントしている。本当の read システムコールを使いたければ、sysread を参照せよ。See sysread.

seek
----

seek(FILEHANDLE,POSITION,WHENCE)

     FILEHANDLE のファイルポインタを任意の位置に移動する。 stdio のfseek() と同じである。 FILEHANDLE はファイルハンドルの名前を値として持つ expression でもよい。成功すれば 1、そうでなければ 0 である。

sprintf
-------

sprintf(FORMAT,LIST)

     通常の printf の習慣でフォーマットされた文字列を返す。

     文字 * はサポートしていない。

sysread
-------

sysread(FILEHANDLE,SCALAR,LENGTH,OFFSET)
sysread(FILEHANDLE,SCALAR,LENGTH)

     システムコール read(2) を用いて、指定したファイルハンドルから変数 SCALAR に LENGTH バイトのデータを読み込む。

     これは stdio を経由しないので、他の種類の読み込みと一緒に使うと混乱することがある。

     実際に読んだバイト数を返す。エラーがあった場合は undef を返す。

     読み込んだデータを文字列の先頭からではなく別の位置に格納するために、 OFFSET を指定してもよい。

syswrite
--------

syswrite(FILEHANDLE,SCALAR,LENGTH,OFFSET)
syswrite(FILEHANDLE,SCALAR,LENGTH)

     システムコール write(2) を用いて、指定したファイルハンドルに変数 SCALAR から LENGTH バイトのデータを書き込む。

     これは stdio を経由しないので、 print と一緒に使うと混乱することがある。

     実際に書き込んだバイト数を返す。エラーがあった場合は undef を返す。

     書き込むデータを文字列の先頭からではなく別の位置から取り出すために、 OFFSET を指定してもよい。

tell
----

tell(FILEHANDLE)
tell FILEHANDLE
tell

     FILEHANDLE の現在のファイル位置を返す。 FILEHANDLE は実際のファイルハンドルの名前を値として持つ expression であってもよい。 FILEHANDLE を省略すると、最後に読んだファイルを仮定する。

write
-----

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/パターン/
-------

m/PATTERN/gio

/PATTERN/gio

     文字列中のパターンマッチを検索し、 true(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/パターン/置き換え/
------------

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
-----

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/検索リスト/置換リスト/
---------------

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/検索リスト/置換リスト/
--------------

y/SEARCHLIST/REPLACEMENT/

     tr/検索リスト/置換リスト/ と同じ。前項を参照。

システム関数
======

alarm
-----

alarm(SECONDS)
alarm SECONDS

     指定した秒数(実際は 1 を引いたもの)が経過した後、 SIGALRM をプロセスに伝える。つまり、 alarm(15) はそれから 14 秒以上経ったある時点で SIGALRM を起こす。

     同時には一つのタイマーしかカウントできない。コールする度に前のタイマーを使えなくするし、また引数として 0 を与えると新しいタイマーを開始せずに前のタイマーをキャンセルする。

     返り値は前のタイマーに残っていた時間である。

chdir
-----

chdir(EXPR)
chdir EXPR

     成功なら 1、失敗なら 0。EXPR 省略時はホームディレクトリ。

chroot
------

chroot(FILENAME)
chroot FILENAME

     同名のシステムコールと同じ。成功/失敗により true/false が返る。 FILENAME が省略された場合、$_ に chroot する。

die
---

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
----

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
----

exit(EXPR)
exit EXPR

     EXPR を評価し、その値で直接 exit する。

                  $ans = <STDIN>;
                  exit 0 if $ans =~ /^[Xx]/;

     EXPR を省略すると、status 0 で exit する。

     See die.

fork
----

fork

     fork() コールを行う。親プロセスには子供のプロセス ID を返し、子プロセスには 0 を返す。

     注意:

     両方のプロセスにおいてフラッシュされていないバッファはフラッシュされずに残るので、だぶって出力されるのを防ぐには、 $| をセットする必要がある。

     See $vline for $|.

getlogin
--------

getlogin

     (もしあれば)/etc/utmp から、現在の login を読んで返す。ヌルの場合は、getpwuid を使うこと。

          $login = getlogin || (getpwuid($<))[0] || "Somebody";

     See Info from system files.

getpgrp
-------

getpgrp(PID)
getpgrp PID

     指定した PID のプロセスグループを返す。 getpgrp(2) をインプリメントしていないマシンで使用すると致命的エラーとなる。 EXPR を省略すると、現プロセスのプロセスグループを返す。

getppid
-------

getppid

     親プロセスのプロセス ID を返す。

getpriority
-----------

getpriority(WHICH,WHO)

     プロセス、プロセスグループ、またはユーザの現在の priority を返す。 (getpriority(2) を参照のこと。) getpriority(2) をインプリメントしていないマシンで使用すると致命的エラーとなる。

kill
----

kill(LIST)
kill LIST

     リストで示されるプロセスにシグナルを送る。リストの第一要素は送るべきシグナルでなければならない。シグナル送信に成功したプロセスの数を返す。

          $cnt = kill 1, $child1, $child2;
          kill 9, @goners;

     シグナルが負の場合、プロセスではなくプロセスグループを kill する。 (System V では、負のプロセス番号はプロセスグループも kill するが、互換性はない。) シグナル名を指定してもよい。

setpgrp
-------

setpgrp(PID,PGRP)

     カレントプロセスグループを指定した値 PID にセットし、カレントプロセスを 0 にする。

     setpgrp(2) をインプリメントしていないマシンでは致命的エラーとなる。

setpriority
-----------

setpriority(WHICH,WHO,PRIORITY)

     あるプロセス、プロセスグループ、またはユーザのカレントプライオリティをセットする。

     setpriority(2) をインプリメントしていないマシンでは致命的エラーとなる。

     (setpriority(2) を参照。)

sleep
-----

sleep(EXPR)
sleep EXPR
sleep

     EXPR 秒の間(EXPR を省略すると、永久に)スクリプトを停止する。プロセスに SIGALRM を送ると interrupt できるだろう。実際に停止した時間を返す。

     おそらく alarm と sleep を混在させることはできないだろう。 sleep() は alarm() を用いてインプリメントされている場合が多いからだ。

syscall
-------

syscall(LIST)
syscall LIST

     LIST の最初の要素で指定するシステムコールを行う。残りの要素はシステムコールの引数として渡される。インプリメントされていない場合は致命的エラーとなる。引数は以下のように解釈される。

       * 引数が数の場合、整数として渡される。

       * そうでない場合はその文字列値へのポインタが渡される。

     文字列に書き込まれるどんな結果でも受け取れるように、文字列の長さを充分取るのはプログラマの責任である。整数の引数が数字ではなく、数であるというコンテキストで解釈されていない場合は、数であることを示すために 0 を足す必要があるだろう。

          require 'syscall.ph'; # h2ph の必要があるかもしれない
          syscall(&SYS_write, fileno(STDOUT), "hi there\n", 9);

system
------

system(LIST)
system LIST

     exec LIST と全く同じことをするが、違いは最初に fork を行い、親プロセスは子プロセスが完了するのを待つ点である。

     注意: 引数の処理は引数の数によって変わる。

     返り値はプログラムの exit status で、wait() と同じである。

     実際の exit value を得るには、256 で割る必要がある。

     See exec.

times
-----

times
     現在のプロセスおよび子プロセスのユーザ、システムタイム(秒)を持つ 4 要素の配列を返す。

          ($user,$system,$cuser,$csystem) = times;

umask
-----

umask(EXPR)
umask EXPR
umask

     プロセスの umask をセットし、変更前の値を返す。 EXPR を省略すると、現在の値を返すだけである。

wait
----

wait

     子プロセスが terminate するのを待ち、死んだプロセスの PID、または子プロセスがない時は -1 を返す。 status は $? に返る。See waitpid.

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
----

warn(LIST)
warn LIST

     die のようにメッセージを STDERR に出すが、exit しない。

ネットワーク関数
========

accept
------

accept(NEWSOCKET,GENERICSOCKET)

同名のシステムコールと同じ。成功/失敗により true/false が返る。

bind
----

bind(SOCKET,NAME)

同名のシステムコールと同じ。成功/失敗により true/false が返る。

connect
-------

connect(SOCKET,NAME)

同名のシステムコールと同じことをする。成功すれば真を、そうでなければ偽を返す。 NAME はソケットに適切な型のパッケージアドレスでなくてはならない。プロセス間通信の章の例を参照のこと。See Interprocess communication.

getpeername
-----------

getpeername(SOCKET)

SOCKET コネクションのもう一方のパックされた sockaddr アドレスを返す。

     # インターネットソケットアドレス
     $sockaddr = 'S n a4 x8';
     $hersockaddr = getpeername(S);
     ($family, $port, $heraddr) =
             unpack($sockaddr,$hersockaddr);

getsockname
-----------

getsockname(SOCKET)

SOCKET コネクションのこちら側のパックされた sockaddr アドレスを返す。

     # インターネットソケットアドレス
     $sockaddr = 'S n a4 x8';
     $mysockaddr = getsockname(S);
     ($family, $port, $myaddr) =
             unpack($sockaddr,$mysockaddr);

getsockopt
----------

getsockopt(SOCKET,LEVEL,OPTNAME)

リクエストされたソケットオプションを返す。エラーがある場合には undefined が返る。

listen
------

listen(SOCKET,QUEUESIZE)

listen システムコールと同じことをする。成功すれば真、そうでなければ偽を返す。プロセス間通信の章の例を参照。 See Interprocess communication.

recv
----

recv(SOCKET,SCALAR,LEN,FLAGS)

ソケットからメッセージを受け取る。ファイルハンドル SOCKET からLENGTH バイトのデータを受け取り、 SCALAR に格納する。 sender のアドレスを返す。エラーがあると、undefined value を返す。 SCALAR は実際に読み込んだバイト数に合わせてサイズが変わる。同名のシステムコールと同じフラグを用いる。

send
----

send(SOCKET,MSG,FLAGS,TO)
send(SOCKET,MSG,FLAGS)

SOCKET にメッセージを送る。同名のシステムコールと同じフラグを使う。コネクトしていないソケットに対しては、メッセージを送る送り先 TO を指定しなければならない。送った文字数を返す。エラーがあった場合は undefined を返す。

setsockopt
----------

setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)

リクエストされたソケットオプションをセットする。エラーがあった場合には undefined を返す。引数を送りたくない時には OPTVAL に undef を指定することができる。

shutdown
--------

shutdown(SOCKET,HOW)

HOW で示す manner でソケットコネクションをシャットダウンする。 HOW は同名のシステムコールと同じように解釈される。

socket
------

socket(SOCKET,DOMAIN,TYPE,PROTOCOL)

指定した種類のソケットをオープンし、ファイルハンドル SOCKET に結び付ける。 DOMAIN、TYPE、PROTOCOL には同名のシステムコールと同じものを指定する。 perl ライブラリファイルから手軽に適切な値を得るためには、 sys/socket.h に対して h2ph を走らせる必要があるかも知れない。

成功すれば真を返す。プロセス間通信の章の例を参照。 See Interprocess communication.

socketpair
----------

socketpair(SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL)

指定した DOMAIN に、指定した TYPE の無名のソケットのペアを作成する。 DOMAIN、TYPE、PROTOCOL は同名のシステムコールと同じものを指定する。インプリメントされていない場合は、致命的エラーとなる。成功すれば真を返す。

System V IPC 関数
===============

msgctl
------

msgctl(ID,CMD,ARG)

System V IPC 関数 msgctl を呼ぶ。 CMD が &IPC_STAT である場合は、 ARG は変数でなければならず、これに msqid_ds 構造体が返ってくる。

ioctl と同様の値を返す。すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真、その他の場合は実際の返り値が返る。

msgget
------

msgget(KEY,FLAGS)

System V IPC 関数 msgget を呼ぶ。メッセージキュー ID を返す。エラーがあれば undefined の値を返す。

msgsnd
------

msgsnd(ID,MSG,FLAGS)

System V IPC 関数 msgsnd を呼び、メッセージキュー ID が ID のメッセージにメッセージ MSG を送る。 MSG の始まりはメッセージ型が long integer でなければならない (これは pack("L", $type) で作成できる)。成功すれば真、エラーがあれば偽を返す。

msgrcv
------

msgrcv(ID,VAR,SIZE,TYPE,FLAGS)

System V IPC 関数 msgrcv を呼び、メッセージキュー ID からのメッセージを受け取って変数 VAR に最大メッセージサイズ SIZE で格納する。

注意: メッセージを受け取った場合、メッセージ型は VAR に格納した最初のものになる。また、VAR の最大サイズは SIZE + メッセージ型のサイズになる。

成功すれば真を返し、エラーがあれば偽を返す。

semctl
------

semctl(ID,SEMNUM,CMD,ARG)

System V IPC 関数 semctl を呼ぶ。 CMD が &IPC_STAT または &GETALL なら、 ARG は変数でなければならず、これに semid_ds 構造体またはセマフォ値の配列が返る。

ioctl と同様の値を返す。すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真、その他の場合は実際の返り値が返る。

semget
------

semget(KEY,NSEMS,SIZE,FLAGS)

System V IPC 関数 semget を呼ぶ。セマフォ ID を返す。エラーの場合は undefined の値を返す。

semop
-----

semop(KEY,OPSTRING)

System V IPC 関数 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
------

shmctl(ID,CMD,ARG)

System V IPC 関数 shmctl を呼ぶ。 CMD が &IPC_STAT である場合は、 ARG は変数でなければならず、これに shmid_ds 構造体が返ってくる。

ioctl と同様の値を返す。すなわち、エラーがあれば undefined の値、ゼロの場合は 0 だが真、その他の場合は実際の返り値が返る。

shmget
------

shmget(KEY,SIZE,FLAGS)

System V IPC 関数 shmget を呼ぶ。共有メモリ ID を返す。エラーがあれば undefined の値を返す。

shmread
-------

shmwrite
--------

shmread(ID,VAR,POS,SIZE)
shmwrite(ID,STRING,POS,SIZE)

System V 共有メモリセグメント 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

がそれぞれ入る。

  * get*nam または get*byname

     getpwnam(NAME), getgrnam(NAME), gethostbyname(NAME), getnetbyname(NAME),

     getprotobyname(NAME), getservbyname(NAME,PROTO)

  * get*[ug]id

     getpwuid(UID), getgrgid(GID)

  * get*by[addr,number,port]

     gethostbyaddr(ADDR,ADDRTYPE), getnetbyaddr(ADDR,ADDRTYPE),

     getprotobynumber(NUMBER), getservbyport(PORT,PROTO)

  * get*ent

     getpwent, getgrent, gethostent, getnetent, getprotoent, getservent

  * set*ent

     setpwent, setgrent, sethostent(STAYOPEN), setnetent(STAYOPEN),

     setprotoent(STAYOPEN),setservent(STAYOPEN)

  * end*ent

     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
------

caller(EXPR)
caller

     サブルーチンコールの現在のコンテキストを返す。

          ($package,$filename,$line) = caller;

     EXPR を指定すると、デバッガがスタックトレースを出力するために使用する情報も返す。 EXPR の値が、現在のサブルーチンの前に call フレームがいくつあるかを示す。

defined
-------

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
----

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
-----

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
-

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
-------

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
-----

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
------

scalar(EXPR)

     EXPR を強制的にスカラーのコンテキストで解釈させ、その値を返す。

undef
-----

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
---------

wantarray

     現在実行中のサブルーチンのコンテキストが配列値を要求していれば true を返す。コンテキストがスカラーを要求していれば false を返す。

          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 は通常と同じ意味を持つ。

  * character class の中では、 \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 種類のどれかである。

 1. コメント

 2. 1 出力行のフォーマットを示す picture 行。

 3. 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 でリセットすることができるようにするため、そうはしなかった。このため、わけの分からないシンボル名で苦労しなければならない。

ほとんどのものはそれなりに覚え易いものまたはシェル変数と似たものにしてある。

<texinfo の作者より> ノード名を全角から半角に変更しましたが、@ など、ノード名にそのまま使うと不都合が起こる文字があるため、実際のノード名を変数名と異なるものにしている場合があります。ご注意下さい。

―――――――――― 予約変数のサブノード ――――――――――――

$_ : 入力およびパターン検索におけるデフォルト
=========================

$_ : 入力およびパターン検索におけるデフォルト。

次の式のペアはそれぞれ等価である。

     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 関数の引数の出力セパレータ

通常、 print はコンマで区切られたフィールドをそのまま(何もつけずに)出力する。 awk のように出力するには、awk 変数 OFS にセットする値 (フィールド間を何で区切るか)をこの変数にセットする。

覚え方:

print 関数において , で区切ると出力される文字。

$" : 配列値を "" で囲んだ時に要素間に入るセパレータ
==============================

$" : 配列値を "" で囲んだ時に要素間に入るセパレータ

配列値が " で囲まれた文字列に変換される時 (または同様に変換される文字列)に適用される点を除いて、 $, と同じ。デフォルトはスペース。

覚え方:

明らかだと思うのだが。

$\ : print 関数の最後に出力するセパレータ
==========================

$\ : print 関数の最後に出力するセパレータ

通常、print はコンマで区切られたフィールドを出力する時、最後に newline やレコードセパレータをつけずに出力する。 awk のように出力するには、awk の ORS 変数にセットする値 (print の最後に何を出力するか)をこの変数にセットする。

覚え方:

print の最後に \n をつける替わりに $\ をセットする。また、\ は / と似ているが、それは``逆に'' perl からデータを受け取る時に使う。

$# : 数字の出力フォーマット
================

$# : 数字の出力フォーマット

この変数は、 awk の OFMT 変数を不完全にエミュレートしようとしたものである。だが、awk と perl で``何が数値か''を判断する際に違いが出ることがある。また、初期値は %.6g ではなく %.20g であるので、 awk と同じ出力を得るには、$# をセットする必要がある。

覚え方:

# は数を表す。

$% : チャンネルの現在のページ番号
===================

$% : 現在セレクトされている出力チャンネルの現在のページ番号。

覚え方:

nroff において % はページ番号である。

$= : 出力チャンネルの現在のページ長さ
=====================

$= : 現在セレクトされている出力チャンネルの現在のページ長さ (出力可能行数)。

デフォルトは 60。

覚え方:

= は水平な線からできている。

$- : 出力チャンネルのページに残っている行数
========================

$- : 現在セレクトされている出力チャンネルのページに残っている行数。

覚え方:

ページの行数 - 出力した行数。

$~ : 出力チャンネルの現在のレポートフォーマット名
===========================

$~ : 現在セレクトされている出力チャンネルの現在のレポートフォーマットの名前。デフォルトはファイルハンドル名。

覚え方:

$^ の兄弟。

$^ : 出力チャンネルの現在のページトップ名
=======================

$^ : 現在セレクトされている出力チャンネルの現在のページトップの名前。デフォルトはファイルハンドル名に "_TOP" をつけたもの。

覚え方:

ページのトップを指している。

$| : write または print の後にフラッシュを行うか否か
===================================

$| : write または print の後にフラッシュを行うか否か

非 0 にセットすると、現在セレクトされている出力チャンネルに対する全ての write または print の後にフラッシュを行う。デフォルトは 0 である。

STDOUT は端末への出力は行バッファリングされ、それ以外はブロックバッファリングされることに注意。この変数をセットすると、perl スクリプトを rsh の下で走らせて、何が起こっているかをその時に見たい場合など、パイプに出力する際に便利である。

覚え方:(?)

(when you want your pipes to be piping hot.)

$$ : スクリプトを走らせている perl のプロセス番号
==============================

$$ : スクリプトを走らせている perl のプロセス番号。

覚え方:

シェルと同じ。

$? : パイプのクローズ、system 関数などで返ったステータス
==================================

$? : 最後のパイプのクローズ、`コマンド`、 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 : 実行している 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 の現在の値を返す。 (つまり、システムエラーを示す特定のエラーが返ったのでないかぎり、 $! の値は意味がないことになる。)

文字列のコンテキストで使うと、システムエラー文字列を返す。

errno をセットするために $! に代入することができる。

例えば、$! にエラー n に対応する文字列を入れて返す場合、または die 関数の終了値をセットしたい場合、など。

覚え方:

What just went bang?

$@ : 最後に行った eval のシンタックスエラーメッセージ
================================

$@ : 最後に行った eval コマンドのシンタックスエラーメッセージ。

ヌルならば、最後に行った eval は解析・実行が正しく行われたことを示す。 (起動した処理は普通に [in a normal fashion] 失敗したかもしれないが)

覚え方:

Where was the syntax error "at"?

$< : プロセスの実 uid
===============

$< : プロセスの実 uid。

覚え方:

setuid スクリプトを走らせている場合、君はどこから来たのか?

$> : プロセスの実効 uid
================

$> : プロセスの実効 uid。

(例)

     $< = $>;  # 実 uid を実効 uid にセットする
     ($<,$>) = ($>,$<);  # 実 uid と実効 uid を入れ替える

覚え方:

setuid スクリプトを走らせている場合、君はどこへ行ったのか?

(注意)

$< や $> は、 setreuid() をサポートしているマシンでのみ swap できる。

$( : プロセスの実 gid
===============

$( : プロセスの実 gid。

同時に複数のグループに属することをサポートするマシンでは、スペースで区切られたユーザが属しているグループのリストとなる。最初のものは getgid() で得られるものである。残りは getgroups() で得られるものであり、その内の一つは最初のものと同じかも知れない。

覚え方:

parentheses are used to GROUP things. The real gid is the group you LEFT, if you're running setgid.

$) : プロセスの実効 gid
================

$) : プロセスの実効 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 で文字列を分ける際の直前の文字列セット

format において、文字列が分けられて継続フィールド (^ で始まる)に入る時のその直前の文字セット。デフォルトは  \n- で、文字列はホワイトスペース又はハイフンの後で分けられる。

覚え方:

a "colon" in poetry is a part of a line.

$^D : デバッグフラグの値
===============

$^D : 現在のデバッグフラグの値。

覚え方:

-D スイッチの値。

$^F : システムファイルディスクリプタの最大値
=========================

$^F : システムファイルディスクリプタの最大値で、通常 2。

システムファイルディスクリプタは子プロセスに渡されるが、それより値が大きいファイルディスクリプタは渡されない。 open の際には、たとえ open が失敗してもシステムファイルディスクリプタは保存される。通常のファイルディスクリプタは open を試みる前に close される。

覚え方:

-D スイッチの値。

$^I : ファイルをその場で変更する場合の拡張子の値
===========================

$^I : ファイルをその場で変更する場合の拡張子の値。

その場で変更するのを禁止するには、これを undef する。

覚え方:

-i スイッチの値。

$^P : デバッガ用内部フラグ
================

$^P : デバッガが自分自身をデバッグしないためにクリアする内部フラグ。

これをクリアすることで自分自身をデバッグすることを不可能にすることが考えられる。

$^T : スクリプトの実行が始まった時刻
=====================

$^T : スクリプトの実行が始まった時刻(epoch からの秒数)。

ファイルテスト -M,-A,-C で返る値はこの値に基づいている。

$^W : 警告スイッチの値
==============

$^W : 現在の警告スイッチの値。

覚え方:

-w スイッチに関連した値。

$^X : Perl が起動された際の名前
=====================

$^X : Perl そのものが起動された際の名前。argv[0] から得る。

$ARGV : <> から読み込んでいるときのカレントファイル名
================================

$ARGV : <> から読み込んでいる時、カレントファイル名が入っている。

@ARGV : スクリプトに与えられたコマンドライン引数
============================

@ARGV : スクリプトに与えられたコマンドライン引数。

$#ARGV は通常 引数の数 - 1 になっていることに注意。なぜなら、$ARGV[0] は最初の引数であって、コマンドの名前ではないからだ。コマンド名を知るには $0 を見よ。

See $0.

@INC : perl スクリプトを探す場所のリスト
==========================

@INC: perl スクリプトを探す場所のリスト

do EXPR コマンドまたは require コマンドで評価される。

最初は コマンドスイッチ -I で指定した引数 + デフォルト perl ライブラリ

(多分 /usr/local/lib/perl、次に . すなわちカレントディレクトリ )が入っている。

%INC : インクルードしたファイルの位置
======================

%INC : インクルードしたファイルの位置

連想配列 INC には do または require を用いてインクルードされたファイル名が入っている。 key は指定したファイル名、 value はファイルが実際に見つかった場所である。

require コマンドはこの配列を用いて指定したファイルが既にインクルードされたかどうかを決定する。

%ENV : 環境変数
===========

%ENV : 現在の環境。

ENV の値を変更すると、子プロセスの環境も変わる。

%SIG : signal ハンドラのリスト
======================

%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 パッケージにおいてサブルーチン名を使用可能とするために、サブルーチン名の前にパッケージ名をつけなければならないことに注意。

プログラミングスタイル
***********

プログラマには皆、当然ながら、体裁に関して自分自身の好みがあるが、プログラムを読み易くするための一般的なガイドラインがいくつかある。

 1. あることをある方法でできるからといって、それはその方法でせねばならないということではない。

     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.

     あやふやでない時でも、君の後を継いでコードのメンテナンスをしなければならない人物の精神福利を考えよう。彼はおそらく誤った所に括弧をつけるだろう。

 2. ループの最初や最後でループから抜けるようなゆがんだことをしてはいけない。

     perl は真ん中から抜けられるように last 宣言子を用意している。見易くするため、インデントを少し少なくしよう。

          line:
           for (;;) {
               statements;
           last line if $foo;
               next line if /^#/;
               statements;
           }

 3. 安心して loop ラベルを使え --- ラベルは多重ループから抜けるためだけでなく、より読み易くするためにある。

     一つ前の例を見よ。

 4. 移植性を高めるには、全マシンでインプリメントされていない機能を使う際に、 eval 構造の中でそれが失敗するかどうかテストせよ。

     ある機能がどのバージョン、どのパッチレベルでインプリメントされたかが分かっているなら、 $] を使ってその機能があるかどうかを調べることができる。

 5. 覚え易い識別子を選べ。

 6. 首尾一貫。(Be consistent.)

perl デバッガ
*********

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
     トレースモードを on/off するトグル。

b line condition
     ブレークポイントをセットする。行を省略すると、次に実行される現在行にセットする。コンディションを指定すると、その文に来る度に評価され、コンディションが真の時のみブレークポイントとして扱われる。ブレークポイントは実行可能な文の最初の行にのみセット可能である。

b subname condition
     サブルーチンの最初の実行可能行にブレークポイントをセットする。

d line
     ブレークポイントを削除する。行を省略すると、次に実行される現在行のブレークポイントを削除する。

D
     全ブレークポイントを削除する。

a line command
     行にアクションをセットする。複数行のコマンドは改行の前にバックスラッシュをつけることで入力可能である。

A
     全ての行アクションを削除する。

< command
     デバッガがプロンプトを出す前に実行するアクションをセットする。複数行のコマンドは改行の前にバックスラッシュをつけることで入力可能である。

> command
     プロンプトの後、コマンドを入力してスクリプト実行に移る時に実行されるアクションをセットする。複数行のコマンドは改行の前にバックスラッシュをつけることで入力可能である。

V package
     パッケージ内の全変数を表示する。デフォルトは main パッケージである。

! number
     デバッグコマンドを再実行する。番号を省略すると、直前のコマンドを再実行する。

! -number
     指定した数だけ前に実行したコマンドを再実行する。

H -number
     指定した数のコマンドを最後から表示する。 1 文字より長いコマンドのみ表示される。番号を省略すると、全部表示する。

q
^D
     終了。

command
     コマンドを perl の文として実行する。セミコロンをつけなくても自動的につけられる。

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]/';

Setuid スクリプト
************

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 ;

perl の作者
********

Larry Wall <lwall@netlabs.com>

MS-DOS サポートは Diomidis Spinellis <dds@cc.ic.ac.uk>

perl が使用するファイル
**************

-e オプションをつけた時に使用するテンポラリファイル

     /tmp/perl-eXXXXXX

診断
**

コンパイルエラーはエラーの起こった行番号に加えて、次に解析されるはずだったトークンまたはトークンの種類を教えてくれる。 (-e オプションを通して perl に渡されるスクリプトの場合は、各々の -e が 1 行と数えられる。)

さらに Setuid スクリプトの場合には、 Insecure dependency のようなエラーメッセージを起こす場合がある。 Setuid scripts の項を参照。See Setuid scripts.

注意点
***

awk に慣れた人が特に注意すべき点
==================

  * perl では単文全ての後ろにセミコロンをつけなければならない。改行は文の終わりを示さない。

  * if や while を使う時には { } が必要である。

  * perl では変数は $ か @ で始まる。

  * $[ をセットしないかぎり配列添え字は 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            $;

  * よくわからない時は、awk のプログラムを a2p にかけて、その出力を見るとよい。

C に洗脳されたプログラマが特に注意すべき点
======================

  * if や while を使う時には { } が必要である。

  * else if の代わりに elsif を使う。

  * break、continue はそれぞれ last、next となる。

  * switch 文はない。

  * perl では変数は $ か @ で始まる。

  * printf は * をインプリメントしていない。

  * コメントは # で始まる。 /* ではない。

  * どんなものであれ、そのアドレスを得ることはできない。

  * ARGV は大文字でなければならない。

  * link、unlink、rename などの``システム''コールは成功すれば非 0 を返す。0 ではない。

  * シグナルハンドラはシグナルの名前を用いて扱う。番号ではない。

鍛えられた sed プログラマが特に注意すべき点
========================

  * 置換におけるバックリファレンス (マッチ結果の参照)は \ ではなく $ を使う。

  * パターンマッチングのメタキャラクター (、)、| の前にはバックスラッシュをつけない。

  * 範囲演算子は .. であり、コンマではない。 (コンマは C と同じように働く。)

鋭い shell プログラマが特に注意すべき点
=======================

  * 演算子においては、コマンドを '' で括らなければ変数置換が行われる。

  * 演算子は、csh と異なり、返り値をそのまま返す。

  * シェル(特に csh)は各コマンド行について複数レベルの置換を行う。 perl は ""、、<>、検索パターンなど、特定の構造について置換を行う。

  * シェルは一度に少しだけスクリプトを解釈する。 perl は実行する前に全プログラムをコンパイルする。

  * 引数は @ARGV を通して利用可能である。 $1、$2 などではない。

  * 環境は変数として自動的に利用可能にはならない。

訂正および追加
*******

Perl の本、Programming Perl では次の項目を省略あるいは入れ損なっている。

  * 5 ページの例

          eval "/usr/bin/perl

     は以下が正しい。

          eval "exec /usr/bin/perl

  * 195 ページの、System V の sum に相当するプログラムは、極めて小さいファイルでしか動作しない。大きなファイルで用いるには、以下のようにする。

          undef $/;
          $checksum = unpack("%32C*",<>) % 32767;

  * alarm と sleep の記述がシグナル SIGALARM に言及しているが、これらは SIGALRM でなければならない。

  * 本が印刷に回った後で、 $/ に初期値をセットする -0 スイッチが Perl に追加された。

  * -l スイッチが自動的な行末処理を行なうようになった。

  * qx// 構造は と同義になった。

  * ps(1) が表示する引数を変更するために、 $0 に代入を行なうことが可能になった。

  * フォーマットの記述から新フォーマット @###.## が偶然省略された。

  * 印刷時には、置換表現 s///ee が評価を複数回行うことがわかっていなかった。これは仕様と解釈するべきである。

  * (LIST) x $count が配列の繰り返しを行なうようになった。

  * 正規表現の中の括弧の数に制限がなくなった。

  * "" 内において、エスケープが追加された:

     \e,\a,\x1b,\c[,\l,\L,\u,\U,\E.

     最後の 5 つは大/小文字の変換を行なう。

  * 変数 $/ は複数文字のデリミッタとしてセットすることができるようになった。

  * 通常のパターンマッチに g 修飾子がもうけられた。これにより一つの文字列に対し複数のマッチ検索を繰り返すことが可能になった。

  * $^T 以外の、$^X 形式の変数が増えた。

  * FILEHANDLE に対するデフォルトのページ先頭フォーマットは FILEHANDLE_TOP であって top ではない。

  * eval {} と sort {} 構造がバージョン 4.011 で追加された。

バグ
**

perl は型キャスティング、atof()、sprintf()などのさまざまな操作について、あなたのマシンの定義を使っている。

stdio があるストリームの read と write の間に、 seek または eof を必要としているなら perl もそうなる。 (これは sysread() および syswrite() にはあてはまらない。)

どのデータタイプにも決まったサイズの上限はないが(メモリサイズは別)、それでもいくつかの限界がある。

  * 指定する識別子は 255 文字を超えてはならない。

  * -S を使う場合、 PATH のどの要素も 255 文字を超えてはならない。

perl は実際の所は、Pathologically Eclectic Rubbish Lister (病理学的折衷主義くずリスター)の略であるが、私がそう言ったということはだれにも言わないでほしい。