Perl:避免从标准输入贪婪读取?
考虑以下 perl 脚本 (read.pl
):
my $line = <STDIN>;
print "Perl read: $line";
print "And here's what cat gets: ", `cat -`;
如果从命令行执行此脚本,它将获取第一行输入,而 cat
获取其他所有内容,直到输入结束(按下^D
)。
然而,当输入从另一个进程通过管道传输或从文件读取时,情况会有所不同:
$ echo "foo\nbar" | ./read.pl
Perl read: foo
And here's what cat gets:
Perl 似乎在某处逐渐缓冲整个输入,并且使用反引号或系统调用的进程看不到任何输入。
问题是我想对混合
和调用其他进程的脚本进行单元测试。最好的方法是什么?我可以关闭 perl 中的输入缓冲吗?或者我可以以“模仿”终端的方式假脱机数据吗?
Consider the following perl script (read.pl
):
my $line = <STDIN>;
print "Perl read: $line";
print "And here's what cat gets: ", `cat -`;
If this script is executed from the command line, it will get the first line of input, while cat
gets everything else until the end of input (^D
is pressed).
However, things are different when the input is piped from another process or read from a file:
$ echo "foo\nbar" | ./read.pl
Perl read: foo
And here's what cat gets:
Perl seems to greadily buffer the entire input somewhere, and processes called using backticks or system do no see any of the input.
The problem is that I'd like to unit test a script that mixes <STDIN>
and calls to other processes. What would be the best way to do this? Can I turn off input buffering in perl? Or can I spool the data in a way that will "mimic" a terminal?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这不是 Perl 问题。这是一个 UNIX/shell 问题。当您运行不带管道的命令时,您处于行缓冲模式,但是当您使用管道重定向时,您处于块缓冲模式。您可以通过以下内容看到这一点:
这个 C 程序也有同样的问题:
This is not a Perl problem. It is a UNIX/shell problem. When you run a command without pipes you are in line buffering mode, but when you redirect with pipes, you are in block buffering mode. You can see this by saying:
This C program has the same problem:
我有好消息和坏消息。
好消息是对 read.pl 的简单修改允许您给它假输入:
示例运行:
坏消息是您会得到一次切换:如果您尝试重复 read-then-cat ,第一个
cat
将使所有后续读取陷入饥饿。要看到这一点,请考虑一个示例运行,该运行会产生
I have good news and bad news.
The good news is a simple modification of
read.pl
allows you to give it fake input:Sample run:
The bad news is you get a single switchover: if you try to repeat the read-then-cat, the first
cat
will starve all subsequent reads. To see this, considerand then a sample run that produces
今天我想我已经找到了我需要的东西:Perl 有一个名为 Expect 的模块,它非常适合此类情况:
就像一个魅力;)
Today I think I've found what I needed: Perl has a module called Expect which is perfect for such situations:
Works like a charm ;)
这是我发现的一种次优方法:
它是次优的,因为人们需要知道程序在等待更多输入之前将发出的“提示”。
另一个次优解决方案如下:
它不需要了解任何提示,但速度很慢,因为它至少等待两秒钟。另外,我不明白为什么需要第二个计时器(否则完成将不会返回)。
有人知道更好的解决方案吗?
Here's a sub-optimal way that I've found:
It's sub-optimal in the sense that one needs to know the "prompt" that the program will emit before waiting for more input.
Another sub-optimal solution is the following:
It does not require knowledge of any prompt, but is slow because it waits at least two seconds. Also, I don't understand why the second timer is needed (finish won't return otherwise).
Does anybody know better solutions?
最后我得到了以下解决方案。虽然还远未达到最佳状态,但它确实有效。即使在像gbacon描述的情况的情况下也是如此。
使用示例(稍微修改过的 read.pl 来测试 gbacon 的情况):
不过,我愿意接受更好的解决方案......
Finally I ended up with the following solution. Still far from optimal, but it works. Even in situations like the one described by gbacon.
Usage example (with a slightly modified read.pl to test gbacon's case):
Still, I'm open to better solutions...