我在工作中构建了一个简单的文本处理脚本,供另一个程序使用 . 当我完成后,有人记得脚本不需要阻止STDIN / STDOUT使用它正常工作的工具,并相应地修改脚本 . 该脚本通过IPC::Open2在子进程中打开* nix的 cat
并将STDIN打印到它,读取它然后处理并将其打印到STDOUT . 我不知道如何使脚本无阻塞,但它显然有效 .
我希望它也适用于Windows,所以我为 type CON
更改了 cat
,这是一个用于打印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并通过它输入管道”技巧呢?
1 回答
这不是Windows verus Linux的事情 . 你只是选了两个可怕的例子 .
type con
从控制台读取,而不是从STDIN读取 . 这可以使用type con <nul
看到 .cat
非常不寻常 . 在任一系统上缓冲完全取决于单个应用程序,但几乎所有应用程序都以相同的方式工作,并且与cat
的工作方式不同 .cat
竭尽全力使这个场景发挥作用 .将
cat
替换为perl -pe1
以查看几乎所有其他程序的行为:说服那些"normal"程序行缓冲而不是块缓冲其输出的方法是创建一个伪tty . 例如,这就是Expect和
unbuffer
所做的 . 当然,这对于Windows程序根据缓冲区做出的决定是不确定的,但我从来没有听说过如何做到这一点 .