我想从Perl运行一个子命令(或将其传递给Perl脚本)并让脚本立即处理命令的输出,而不是等待超时,换行或一定数量的块。例如,假设我想用方括号括住每个输入块。当我像这样运行脚本时:
$ ( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz) | my_script.pl
我希望输出为此,每行显示前一行后五秒:
[foo]
[bar]
[baz]
我该怎么做?
这很有效,但真的很难看:
#! /usr/bin/perl -w
use strict;
use Fcntl;
my $flags = '';
fcntl(STDIN, F_GETFL, $flags);
$flags |= O_NONBLOCK;
fcntl(STDIN, F_SETFL, $flags);
my $rin = '';
vec($rin,fileno(STDIN),1) = 1;
my $rout;
while (1) {
select($rout=$rin, undef, undef, undef);
last if eof();
my $buffer = '';
while (my $c = getc()) {
$buffer .= $c;
}
print "[$buffer]\n";
}
有更优雅的方式吗?
答案 0 :(得分:9)
来自perlfaq5:How can I read a single character from a file? From the keyboard?。您可能还想阅读How can I tell whether there's a character waiting on a filehandle?。轮询文件句柄。如果那里有一个字符,请阅读它并重置一个计时器。如果那里没有角色,请再试一次。如果您已重试并经过一段时间,请处理输入。
在您阅读完字符后,您可以决定如何处理这些字符。阅读单个字符的所有灵活性都是处理它们的额外工作。
答案 1 :(得分:4)
Term::ReadKey可以为您完成此操作。特别是设置ReadKey()模式为你进行轮询。
use Term::ReadKey;
$| = 1;
while( my $key = ReadKey(10) ) {
print $key;
}
答案 2 :(得分:1)
如果每个角色之间有时间,您可能能够检测到暂停。
Perl也会进行行输入 - 如果你不使用getc,你应该可以在foo,bar等的末尾添加换行符,perl会给你每一行。
如果您无法添加换行符,并且您不能依赖暂停,那么您希望系统究竟告诉perl它是否已启动新命令?就perl而言,有一个stdin管道,它正在从中获取数据,并且stdin管道中没有任何内容可以告诉你何时执行新命令。
您可以考虑以下内容:
$ echo "( echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz)" | my_script.pl
或
$ my_script.pl$ "echo -n foo ; sleep 5 ; echo -n bar ; sleep 5; echo baz"
修改你的perl程序来解析输入“命令行”并执行每个任务,根据需要吃stdout。
- 亚当
答案 3 :(得分:0)
您没有提到如何阅读Perl脚本中的输入,但您可能希望查看getc
函数:
$|++; # set autoflush on output
while ($c = getc(STDIN)) {
print $c;
}
答案 4 :(得分:0)
请参阅How to change Open2 input buffering。 (基本上,你必须让其他程序认为它与tty交谈。)