前回はバッククォート(``)の使い方について説明しましたが、今回もOSそのものの機能とPerlプログラムを密接に結びつける機能です。

a54d1ba3
 ファイルのopen関数のモードとして、『かんたんPerl』では入力(<)、出力(>)、アペンド(>>)の3つを説明しました。
 どれもコマンドラインのリダイレクションと同じなので覚えやすいですね。

Perlでfile_to_be_read.txtを読み込む:

open IN, "<", "file_to_be_read.txt";

コマンドラインでsortコマンドにfile_to_be_sorted.txtを入力する:

$ sort < file_to_be_sorted.txt

Perlでfile_to_be_written.txtを書き出す:

open OUT, ">", "file_to_be_written.txt";

コマンドラインでlsコマンドの結果をfile_list.txtに出力する:

$ ls -la > file_list.txt

Perlでfile_to_be_written.txtにアペンド(追加)出力する:

open APPEND, ">>", "file_to_be_written.txt";

コマンドラインでxxxディレクトリのlsコマンドの結果をfile_list.txtに追加出力する:

$ ls -la xxx >> file_list.txt

 ここまでは紹介しましたが、モードにはもう1つパイプ(|)というものを使います。
 |(バー)という字を使います。


 バーはパソコン用語ではパイプとも読みます。あるコマンドの出力を別のコマンドに渡すときに使います。

[sample]$ ls -la *.pl | grep 'Feb 12'
-rwxr-xr-x@ 1 query1000 staff 196 Feb 12 20:11 packExample.pl
-rwxr-xr-x@ 1 query1000 staff 213 Feb 12 20:11 packExample2.pl
-rwxr-xr-x@ 1 query1000 staff 263 Feb 12 20:11 unpackExample.pl

 これは「カレントディレクトリの拡張子plのファイルを詳細一覧表示する」というlsコマンドの出力を、「Feb 12という文字列を含む行をフィルタリングする」というgrepコマンドに渡しているものです。結果的に2月12日に作成されたファイルを作成します。

 同様に、パイプ(|)を出力のファイルハンドルのモードに使い、ファイル名の代わりにコマンド名を書くことが出来ます。
 以下のように書きます。

#! /usr/local/bin/perl
#
# pipeExample.pl -- パイプの使用例

use strict;
use warnings;
use utf8;
use 5.10.0;

open PIPE, "| sort";
while (<DATA>) {
 print PIPE if /Feb 12/;
}

__DATA__
Jane Smith, Jan 06
Joe Black, Feb 12
Mike Millar, Feb 06
Jeff Hall, Feb 12
Elvis Wall, Feb 12
Cliford Hacknell, Feb 12

 実行します。

[sample]$ ./pipeExample.pl
Cliford Hacknell, Feb 12
Elvis Wall, Feb 12
Jeff Hall, Feb 12
Joe Black, Feb 12

 これは、「Feb 12」を含むDATA行を出力するプログラムに、sortコマンドをかました例です。
 結果的に出力ファイルがソートされて出てきます。

 注意点は、

open PIPE, "|", "sort";

のように3引数で書けないことです。

 <、>、>>の場合は

open ファイルハンドル, "モード", ファイル名;

という3引数で書くことが推奨されています。

open ファイルハンドル, "モード ファイル名";

のように2引数で書くのは古い書き方で、もしファイル名が変数だった場合にUNIXのコマンドを紛れ込ませるクラッキングを許すセキュリティ ホールになってしまうので、非推奨です。しかし、パイプの場合は

open ファイルハンドル, "| コマンド名";

のようにしか書けません。もし

open ファイルハンドル, "|", "コマンド名";

みたいに書くと

Unknown open() mode '|' at ./pipeExample.pl line 10.

のように怒られます。

 上の例のようにsortコマンドを書くと、出力をソートできて便利ですが、この例の場合は


#! /usr/local/bin/perl
#
# noPipeExample.pl -- パイプを使わない

use strict;
use warnings;
use utf8;
use 5.10.0;

print sort grep {/Feb 12/} <DATA>;

__DATA__
Jane Smith, Jan 06
Joe Black, Feb 12
Mike Millar, Feb 06
Jeff Hall, Feb 12
Elvis Wall, Feb 12
Cliford Hacknell, Feb 12

とPerl内蔵のsort関数を使えばオッケーですね。

 他にも、文字コードを変換するnkfコマンドをパイプでopenすると、出力ファイルの文字コードを変えられるとか昔は使っていたのですが、今ではPerl内蔵のUnicode機能を使ったほうがはるかに便利です。

 パイプはOSのコマンドを直接呼び出すので``同様プログラムのポータビリティが落ちますし、Perl自身の機能を使った方がカンタンでカッコイイ場合が多いと思ったので、あえて本では紹介しなかったんです。

【2016-02-17補足】
 Twitterでご教示をいただきました。
 以下のようにすると3引数のopenでパイプを使うことができるそうです。

open ファイルハンドル, "|-", "コマンド名";

 なるほどー! ご指摘ありがとうございました!!