2015-06-17 5 views
0

Я построил простой скрипт обработки текста на работе, который будет использоваться другой программой. Когда я закончил, кто-то вспомнил, что сценарий не должен блокировать STDIN/STDOUT для того, чтобы инструмент использовал его для правильной работы и соответствующим образом изменил сценарий. Сценарий открывает * nix cat в подпроцессе через IPC::Open2 и печатает на нем STDIN, считывает его и затем обрабатывает и печатает его в STDOUT. Я понятия не имею, как это делает скрипт не блокирующим, но он, по-видимому, работал.Windows/Linux дочерний процесс STDIN отличия

Я хотел, чтобы он работал и на Windows, поэтому я изменил cat на type CON, что является простой командой Windows для печати STDIN. Пример сценария ниже:

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 (I тип 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? Кроме того, почему этот «открытый кот в подпроцессе и трубе ввода через него» вообще работает?

+0

@Harry Johnston, Двухсторонняя интерактивная связь с дочерним процессом. – ikegami

+0

@harry Johnston, На практике это будет более сложная программа. – ikegami

+0

@Nate: причина, по которой сценарий, как написано, ведет себя странно, заключается в том, что сценарий и дочерний процесс конкурируют за один и тот же источник ввода. –

ответ

1

Это не Windows-версия Linux verus. Вы просто выбрали два ужасных примера.

  1. type con читает с консоли, а не от STDIN. Это можно увидеть, используя type con <nul.

  2. cat чрезвычайно необычный. Буферизация в любой системе полностью зависит от конкретного приложения, но почти все приложения работают одинаково, и это отличается от того, как работает cat. cat делает все возможное, чтобы этот сценарий работал.

Заменить cat с perl -pe1 увидеть поведение практически любой другой программы:

1 
first line: 1 
<deadlock> 

Путь, чтобы убедить эти «нормальные» программы к линейному буфера, а не блок-буфер их выход в создайте псевдо-tty. Это то, что делает Expect и unbuffer, например. Это, конечно, не будет работать в Windows. Я не уверен, какие программы Windows основывают свое решение на буфере, но я не думаю, что это легко подделать, потому что я никогда не слышал о том, как это сделать.

+0

Почему 'perl -pe1' вызывает тупик? Кроме того, 'type CON' повторяет все, что я набираю в cmd, который, как я предполагал, был STDIN. Что он читает вместо этого? –

+0

@Nate: CON - это консольный вход, то есть клавиатура. –

+1

'' блокирует до получения новой строки от дочернего элемента, но 'child' не будет печатать ничего, пока он не будет иметь 4k (старый по умолчанию Perl) или 8k (новый по умолчанию Perl) данных для печати, из которых он может получить только от его родительский элемент, но его родитель больше не будет отправлять данные, поскольку он заблокирован. – ikegami

Смежные вопросы