我是Perl上的新手,并尝试使用Curses(Curses :: UI)在Perl中执行一个简单的脚本启动器
在Stackoverflow上,我找到了一个实时打印(在Perl中)Bash脚本输出的解决方案。
但我无法用我的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字段末尾写入。
是否有解决方案可以实时显示Shell脚本中发生的情况,而不会阻止Perl脚本?
非常感谢,如果这个问题似乎很愚蠢,那就很抱歉:x
答案 0 :(得分: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
,因为前者会阻止,直到收到换行符。使用read
或readline
等阻止调用无法使用select
。此外,使用read
或readline
等缓冲调用可能会导致select
在实际存在时没有等待。切勿将read
和readline
与select
一起使用。