<>演算子

id:stdio:20070707さん の<>演算子*1 *2について尻馬に乗ってみる。

@ARGVが空であれば、<>は標準入力を求めるようになり、
@ARGVに何かが入っていれば、<>はその引数を取り扱う。

これは今まで知らなかったな。ほとんど標準入力経由で使っていたから。ラクダ本を見ると<>はコマンドライン引数に渡されたすべてのファイルから読み込みコマンドライン引数が空ならSTDINとなる。

今までしてきたのだけども、を<>と省略するのは危険思考で、
と明示的にしたほうがよいのではないか?と少し思った。

これについてはperlはうまくやってくれそうな気がする。というのもrubyはここをうまく処理しているのだ。ラクダ本も上記の説明の後に(ちなみにこれは多くのフィルタプログラムの標準的な動作と同じである。)と書いてある。試してみた。サンプルコードは以下。

# hoge.pl
# 第一引数を与えたときとリダイレクトしたときの差は?
use strict;
print reverse <>;
print "パラメータリスト @ARGV\n"

まぁワンライナーですむようなコードだけど複数行無いと動作確認ができないから。で、動かし方はリダイレクトと引数でファイルを与える2通りのやり方をやってみる。とりあえずスクリプト自身を食わせてみよう。

  1. > perl hoge.pl < hoge.pl
  2. > perl hoge.pl hoge.pl

どちらも実行結果は同じだ。引数にファイルではない文字列を与えると、そんなファイルは無い!っておこられるけどアボートしたりせずに次のファイルを処理してくれる。コマンドライン引数にファイル名以外を渡したいときは別だがあまり心配しなくてもいいかも。


さらに気になって<>の引数自動展開と同等の動作をするコードを書いてみた。

# hoge1.pl
# 引数ファイルハンドル展開と同等コード
use strict;

for (@ARGV) {
    open FH , '<', "$_";
    print reverse <FH>;
    close FH;
}
print "パラメータリスト @ARGV\n"

引数で渡された文字列をファイル名としてあまねく開いて逆順表示。最後に確認のため渡された引数のリストを表示だ。ところが最後のパラメータリストの表示が違った。<>の自動展開の場合は最後のパラメータリストが空になってしまう。何となくshiftしている感じだ。よって<>の自動展開を再現するコードは下記のようになった。

# hoge2.pl
# 引数ファイルハンドル展開と同等コード
use strict;

my $param;
for (;;) {
    $param = shift @ARGV;
    last unless (open FH , '<', "$param");
    print reverse <FH>;
    close FH;
}
print "パラメータリスト @ARGV\n"

*1:id:stdioさんのブログではダイアモンド演算子となっていたがラクダ本の脚注ではアングル演算子となっていた

*2:さらにちなむが<=>はスペースシップ演算子である。ダースべーダが乗っていたのは確かにこんな宇宙船だった。