シェルのない (ただし移植性が低い可能性がある) バージョン:
#!perl
use strict;
use warnings;
use Fcntl;
open my $one, '-|', 'echo', 'string1' or die "$! opening first input";
fcntl $one, F_SETFD, (fcntl($one, F_GETFD, 0) & ~FD_CLOEXEC)
or die "$! keeping open first input";
open my $two, '-|', 'echo', 'string2' or die "$! opening second input";
fcntl $two, F_SETFD, (fcntl($two, F_GETFD, 0) & ~FD_CLOEXEC)
or die "$! keeping open second input";
open my $diff, '-|', 'diff', "/dev/fd/".fileno($one), "/dev/fd/".fileno($two)
or die "$! running diff";
while (<$diff>) {
print;
}
これは基本的にシェルが行うこととまったく同じです (最初の「echo」コマンドのサブプロセスを開き、2 番目の「echo」コマンドのサブプロセスを開き、子プロセスがファイルハンドルを継承できるようにし、「diff」へのサブプロセスを開きます)。その引数は、開いているファイルハンドルを指す特別なファイル名です)。唯一の違いは、diff が画面に出力できるようにするのではなく、出力をキャプチャして自分で出力することです。
新しいバージョン (/bin/echo なし、エスケープなし、デッドロックなし)
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl;
my $pid_one = open my $one, '-|';
die "$! opening first input" unless defined $pid_one;
if (!$pid_one) { # child
print "string1\n";
exit;
}
fcntl $one, F_SETFD, (fcntl($one, F_GETFD, 0) & ~FD_CLOEXEC)
or die "$! keeping open first input";
my $pid_two = open my $two, '-|';
die "$! opening second input" unless defined $pid_two;
if (!$pid_two) { # child
print "string2\n";
exit;
}
fcntl $two, F_SETFD, (fcntl($one, F_GETFD, 0) & ~FD_CLOEXEC)
or die "$! keeping open second input";
open my $diff, '-|', 'diff', "/dev/fd/".fileno($one), "/dev/fd/".fileno($two)
or die "$! running diff";
while (<$diff>) {
print;
}
string1
親プロセスの変数やstring2
他のコマンドの出力など、何でもかまいません。