2012-07-24 61 views
6

我试图设置从Perl的任意管道,在很大程度上与壳可能相同的方式。从perl管道中运行“少”

这预期的效果,这就像 “回声富| sed的S/OO/AR /”:

#!/usr/bin/perl 
use strict; 

use IO::Handle; 

$| = 1; 

my ($first_prog, $second_prog) = ([qw(echo foo)], [qw(sed s/oo/ar/)]); 
#$second_prog = ["less"]; 

pipe(my $second_prog_input, my $first_prog_output) 
    or die "problem setting up pipe: $!\n"; 

if (fork) { 
    STDOUT->fdopen(fileno($first_prog_output), 'w') or die; 
    exec(@$first_prog) or die; 
} 
else { 
    STDIN->fdopen(fileno($second_prog_input), 'r') or die; 
    exec(@$second_prog) or 
     die "couldn't exec: $!: command was @$first_prog\n"; 
} 

然而,当我做第二个参数 “少”,我的终端闪烁,我在寻呼机中看不到输出。除了短暂的闪光之外,没有任何迹象表明可以运行。

现在的东西我没有得到根本的是,以下的不表现得像“回声富|少”:

pipe(my $first_prog_output, STDIN) or die "problem setting up pipe: $!\n"; 

my ($first_prog, $second_prog) = ([qw(echo foo)], ["less"]); 

open($first_prog_output, "-|", @$first_prog) or 
    die "$!: command was @$first_prog\n"; 

exec(@$second_prog) or 
    die "couldn't exec: $!: command was @$first_prog\n"; 

但我完全不知道该怎么管是()的调用这样做。第一个论点应该是“读者”,第二个论点是“作家”。 STDIN是一个“作家”?

我很困惑这一切,并认为可能有一些基本的关于底层的Unix API,我失踪或我忘记了。

回答

6

这是一个有趣计时问题:

  • 壳牌叉,创建一个处理组,设置终端前景组到它,并且高层perl
  • perl分叉和执行less
  • perl高管echo
  • echo退出,shell相信作业已完成,并将其自身设置为终端前台进程组。
  • less试图获得终端。它不在终端前台进程组中。 less失败。

最简单的办法:改变fork!fork(或等价地,交换你ifelse块)。这样,管道的最后阶段就定义了作业的生命周期。 (如果您仔细观察,外壳叉和执行程序在运行管道时也按相同顺序处理。)