【问题标题】:running "less" from perl pipeline从 perl 管道运行“less”
【发布时间】:2012-07-23 08:24:46
【问题描述】:

我正在尝试从 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 的一些基本内容。

【问题讨论】:

    标签: perl exec fork pipe dup


    【解决方案1】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 1970-01-01
      • 1970-01-01
      • 2012-09-19
      相关资源
      最近更新 更多