简体   繁体   English

从perl管道运行“less”

[英]running “less” from perl pipeline

I am trying to set up arbitrary pipelines from Perl, in much the same way as a shell might. 我试图从Perl设置任意管道,就像shell一样。

This has the desired effect, it's like "echo foo | sed s/oo/ar/": 这有所期望的效果,就像“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";
}

However, when I make the second argument "less", my terminal flashes, and I don't see the output in the pager. 但是,当我将第二个参数设置为“less”时,我的终端会闪烁,而我在寻呼机中看不到输出。 Other than the brief flash, there is no sign of less running at all. 除了短暂的闪光,没有任何迹象表明运行较少。

Now something I don't get at all is that the following does behave like "echo foo | 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";

But I don't understand at all what that call to pipe() is doing. 但我完全不了解对pipe()的调用。 The first argument is supposed to be a "reader", and the second one a "writer". 第一个论点应该是“读者”,第二个论点是“作家”。 How is STDIN a "writer"? STDIN如何成为“作家”?

I'm very confused by all this, and think there may be something fundamental about the underlying Unix API that I'm missing or I've forgotten. 我对这一切感到非常困惑,并认为可能存在一些基本的Unix API,我缺少或者我已经忘记了。

It's an interesting timing issue: 这是一个有趣的时间问题:

  • Shell forks, creates a process group, sets the terminal foreground group to it, and execs perl . Shell分支,创建进程组,将终端前台组设置为它,并执行perl
  • perl forks and execs less . perl forks和execs less
  • perl execs echo . perl高管echo
  • echo exits, shell believes job is done and sets itself as the terminal foreground process group once again. echo退出,shell认为作业完成并再次将自己设置为终端前台进程组。
  • less tries to acquire terminal. less尝试获取终端。 It is not in the terminal foreground process group. 它不在终端前台进程组中。 less fails. less失败。

The simplest solution: change fork to !fork (or equivalently, swap your if and else blocks). 最简单的解决方案:将fork更改为!fork (或等效地,交换ifelse块)。 That way, the final stage of the pipeline defines the lifetime of the job. 这样,管道的最后阶段定义了工作的生命周期。 (If you watch carefully, the shell forks and execs processes in this same order when it runs a pipeline, too.) (如果仔细观察,shell在运行管道时也会以相同的顺序分叉和执行进程。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM