我在工作中构建了一个简单的文本处理脚本,供其他程序使用。当我完成后,有人记得脚本不需要阻止STDIN / STDOUT使用它来正常工作,并相应地修改了脚本。该脚本通过IPC::Open2
在子进程中打开* nix的cat
并将STDIN打印到它,读回来然后处理并将其打印到STDOUT。我不知道如何使脚本无阻塞,但它显然有效。
我希望它也可以在Windows上运行,所以我为cat
更改了type CON
,这是一个用于打印STDIN的简单Windows命令。示例脚本如下:
use strict;
use warnings;
use IO::Handle;
use IPC::Open2;
my $command = ($^O eq 'MSWin32') ? 'type CON' : 'cat';
my ( $com_reader, $com_writer ) = ( IO::Handle->new, IO::Handle->new );
open2( $com_reader, $com_writer, $command );
# input
while (<STDIN>) {
print "first line: $_";
print $com_writer "$_";
my $line = <$com_reader>;
# ...process $line...
print "next line: $line";
}
但结果完全不同。在Windows上,主脚本和子脚本的STDIN流似乎不同,而在Linux上它们是相同的。在Windows上(我在单独的输入行上输入1和2):
>perl test.pl
>1
first line: 1
>2
next line: 2
>1
>2
first line: 2
next line: 1
>1
>2
first line: 2
next line: 1
>1
>2
first line: 2
next line: 1
在Linux上(相同输入):
>perl test.pl
>1
first line: 1
next line: 1
>2
first line: 2
next line: 2
>1
first line: 1
next line: 1
>2
first line: 2
next line: 2
为什么输出不同,如何使Windows行为与Linux行为相匹配?另外,为什么这个“在子进程中打开cat并通过它输入管道”技巧呢?
答案 0 :(得分:1)
这不是Windows verus Linux的事情。你只选了两个可怕的例子。
type con
从控制台读取,而不是从STDIN读取。这可以使用type con <nul
。
cat
极不寻常。在任一系统上缓冲完全取决于单个应用程序,但几乎所有应用程序都以相同的方式工作,并且与cat
的工作方式不同。 cat
不遗余力地使这个场景发挥作用。
将cat
替换为perl -pe1
以查看几乎所有其他程序的行为:
1
first line: 1
<deadlock>
说服那些&#34;正常&#34;行缓冲而不是块缓冲它们的输出的程序是创建一个伪tty。例如,这就是Expect和unbuffer
所做的。当然,这在Windows中无法运行。我不确定哪些Windows程序根据他们的缓冲决定,但我不认为它可以很容易伪造,因为我从来没有听说过如何做到这一点。