从perl管道运行“less”

时间:2012-07-24 23:20:00

标签: perl exec fork pipe dup

我正在尝试从Perl设置任意管道,这与shell可能的方式非常相似。

这有预期的效果,就像“echo foo | 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";
}

但是,当我将第二个参数设为“less”时,我的终端会闪烁,而我在寻呼机中看不到输出。除了短暂的闪光之外,根本没有迹象表明运行不足。

现在我根本没有得到的是以下内容的行为类似于“echo foo | less”:

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

但我完全不了解对pipe()的调用是什么。第一个论点应该是“读者”,第二个论点是“作家”。 STDIN如何成为“作家”?

我对这一切感到非常困惑,并认为可能存在一些基本的Unix API,我缺少或者我已经忘记了。

1 个答案:

答案 0 :(得分:6)

这是一个有趣的时间问题:

  • Shell forks,创建一个进程组,将终端前景组设置为它,并执行perl
  • perl分叉和执行less
  • perl高管echo
  • echo退出,shell认为工作已完成,并再次将自己设置为终端前台进程组。
  • less尝试获取终端。它不在终端前台进程组中。 less失败。

最简单的解决方案:将fork更改为!fork(或等效地,更换ifelse块。这样,管道的最后阶段定义了工作的生命周期。 (如果仔细观察,shell在运行管道时也会以相同的顺序分叉和执行进程。)