6

シェルとほぼ同じ方法で、Perl から任意のパイプラインをセットアップしようとしています。

これには望ましい効果があります。「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";
}

ただし、2 番目の引数を「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() の呼び出しが何をしているのかまったくわかりません。最初の引数は「リーダー」で、2 番目の引数は「ライター」です。STDINはどのように「ライター」ですか?

私はこれらすべてに非常に困惑しており、根底にある Unix API について何か基本的なことが欠けているか忘れているのではないかと考えています。

4

1 に答える 1

6

これは興味深いタイミングの問題です。

  • シェルはフォークし、プロセス グループを作成し、ターミナル フォアグラウンド グループをそれに設定し、execs しperlます。
  • perlフォークとエグゼクティブless
  • perl幹部echo
  • echo終了すると、シェルはジョブが完了したと認識し、自分自身を端末フォアグラウンド プロセス グループとして再び設定します。
  • less端末の取得を試みます。端末フォアグラウンド プロセス グループに含まれていません。 less失敗します。

最も簡単な解決策: に変更fork!forkます (または同等に、ifandelseブロックを交換します)。このようにして、パイプラインの最終段階でジョブの有効期間が定義されます。(注意して見ると、シェルは、パイプラインを実行するときにも、この同じ順序でプロセスをフォークして実行します。)

于 2012-07-25T04:35:14.413 に答える