0

私は Perl の初心者で、Curses (Curses::UI) を使用して Perl で簡単なスクリプトのランチャーを実行しようとしています。

Stackoverflow で、Bash スクリプトの出力をリアルタイムで (Perl で) 印刷するソリューションを見つけました。

しかし、私の Curses スクリプトでは、この出力を TextEditor フィールドに書き込むことはできません。

たとえば、Perl スクリプトは次のようになります。

#!/usr/bin/perl -w

use strict;
use Curses::UI;
use Curses::Widgets;
use IO::Select;

my $cui = new Curses::UI( -color_support => 1 );

[...]

my $process_tracking = $container_middle_right->add(
    "text", "TextEditor",
    -readonly       => 1,
    -text           =>  "",
);

sub launch_and_read()
{
    my $s = IO::Select->new();
    open my $fh, '-|', './test.sh';
    $s->add($fh);

    while (my @readers = $s->can_read()) {
        for my $fh (@readers) {
            if (eof $fh) {
                $s->remove($fh);
                next;
            }
            my $l = <$fh>;
            $process_tracking->text( $l );
            my $actual_text = $process_tracking->text() . "\n";
            my $new_text = $actual_text . $l;
            $process_tracking->text( $new_text );
            $process_tracking->cursor_to_end();
        }
    }
}

[...]

$cui->mainloop();

このスクリプトには、launch_and_read() を起動するボタンが含まれています。

そして test.sh :

#!/bin/bash
for i in $( seq 1 5 )
do
    sleep 1
    echo "from $$ : $( date )"
done

その結果、bash スクリプトの実行中にアプリケーションがフリーズし、最終的な出力が最後に TextEditor フィールドに書き込まれます。

Perl スクリプトをブロックせずに、シェル スクリプトで何が起こったかをリアルタイムで表示するソリューションはありますか?

この質問がばかげているように思われる場合は申し訳ありません:x

4

1 に答える 1

0

ブロックすることはできません。イベントを処理するには、curses のループを実行する必要があります。したがって、投票する必要があります。selectゼロのタイムアウトでポーリングに使用できます。

my $sel;

sub launch_child {
   $sel = IO::Select->new();
   open my $fh, '-|', './test.sh';
   $sel->add($fh);
}

sub read_from_child {
   if (my @readers = $sel->can_read(0)) {
      for my $fh (@readers) {
         my $rv = sysread($fh, my $buf, 64*1024);
         if (!$rv) {
            $sel->remove($fh);
            close($fh);
            next;
         }

         ... add contents of $buf to the ui here ...
      }
   }
}

launch_child();
$cui->set_timer(read_from_child => \&read_from_child, 1);
$cui->mainloop();

未テスト。

前者は改行を受信するまでブロックするため、readline( <>) からに切り替えたことに注意してください。またはのsysreadようなブロッキング呼び出しを使用すると、 を使用するポイントが無視されます。さらに、 orのようなバッファリング呼び出しを使用すると、実際には何も待機していないことを示す可能性があります。とを一緒に使用しないでください。readreadlineselectreadreadlineselectreadreadlineselect

于 2013-05-16T07:40:05.757 に答える