Как я могу читать конвейерный ввод в Perl в Windows?

Я пытаюсь создать на Perl что-то похожее на команду Unix tee. Я пытаюсь прочитать каждую строку STDIN, запустить для нее подстановку и распечатать. (И, в конце концов, также распечатать его в файл.) Это работает, если я использую консольный ввод, но если я пытаюсь передать ввод в команду, это ничего не делает. Вот простой пример:

print "about to loop\n";
while(<STDIN>)
{
  s/2010/2009/;
  print;
}
print "done!\n";

Я пытаюсь передать ему команду dir следующим образом:

C:\perltest>dir | mytee.pl
about to loop
done!

Почему он не видит входной канал? (Я использую Perl 5.10.0 на WinXP, если это уместно.)


person Jenni    schedule 19.03.2010    source источник
comment
Кажется, это зависит от ОС, он отлично работает на моем компьютере с OS X.   -  person zoul    schedule 19.03.2010
comment
Это почти дубликат stackoverflow.com/questions/1286873/.   -  person Michael Carman    schedule 07.01.2011


Ответы (5)


На самом деле это ошибка в том, как Windows обрабатывает перенаправление ввода-вывода. Я ищу ссылку прямо сейчас, но это та ошибка, которая требует, чтобы вы указали

dir | perl filter.pl

а не возможность использовать

dir | filter

См. статью Microsoft KB Перенаправление STDIN/STDOUT может не работать, если оно запущено из сопоставления файлов:

  1. Запустите редактор реестра.
  2. Найдите и щелкните следующий ключ в реестре: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer
  3. On the Edit menu, click Add Value, and then add the following registry value:
    • Value name: InheritConsoleHandles
    • Тип данных: REG_DWORD
    • Основание: Decimal
    • Значение данных: 1
  4. Закройте редактор реестра.
C:\Temp> cat filter.pl
#!/usr/bin/perl

while ( <> ) {
    print "piped: $_";
}
C:\Temp> dir | filter
piped:  Volume in drive C is MAIN
piped:  Volume Serial Number is XXXX-XXXX
piped:
piped:  Directory of C:\Temp>
piped:
piped: 2010/03/19  03:48 PM              .
piped: 2010/03/19  03:48 PM              ..
piped: 2010/03/19  03:33 PM                32 m.pm
piped: 2010/03/19  03:48 PM                62 filter.pl
person Sinan Ünür    schedule 19.03.2010
comment
спасибо синан, очень полезный ответ. это делает так, что мне не нужен обходной путь неприглядного пакетного файла - person Jenni; 20.03.2010
comment
@Jenni Недостаток, конечно, в том, что вы не можете быть уверены, что InheritConsoleHandles будет установлен на любых других компьютерах, на которых вы можете развернуть свои скрипты (именно здесь появляется pl2bat.bat). Спасибо, что приняли мой ответ. - person Sinan Ünür; 20.03.2010
comment
Я обнаружил, что эта ошибка Windows не может быть надежно воспроизведена. В первый раз я должен использовать dir | perl filter.pl. Но во второй раз это работает только с dir | filter.pl. Противный. - person smwikipedia; 29.05.2013

Пытаться:

C:\perltest>dir | perl mytee.pl
person codaddict    schedule 19.03.2010
comment
хм... это работает, но почему я должен указывать это именно так? - person Jenni; 19.03.2010
comment
Потому что вы находитесь на окнах. В Unix вы можете поместить #!/usr/bin/perl в начало файла perl, чтобы сообщить оболочке, где находится perl. В Windows напрямую могут выполняться только файлы .exe и .com. - person Byron Whitlock; 19.03.2010
comment
Хорошо, в моем случае c:\scripts находится в %PATH%, а .PL — в %PATHEXT%. я хочу иметь возможность вызывать foo | mytee из любого места, не вспоминая, что в этом случае мне нужно поставить perl перед ним и .pl в конце. есть предложения или мне не повезло? - person Jenni; 19.03.2010
comment
@Jenni Вы можете использовать pl2bat для преобразования вашего Perl-скрипта в пакетный файл, который Windows затем с удовольствием пропустит. - person ephemient; 19.03.2010
comment
хорошо, я нашел обходной путь. Я создаю файл mytee.bat в каталоге c:\scripts. этот bat-файл имеет @echo off в первой строке и perl c:\scripts\mytee.pl %1 %2 во второй строке. это работает - ввод передается через файл bat в скрипт perl. Поскольку .bat находится перед .pl в моем PATHEXT, это делает так, что mytee выполняет mytee.bat, а не сценарий perl. - person Jenni; 19.03.2010

Может ли это быть Microsoft KB #321788?

Сценарии, содержащие стандартный ввод (STDIN) и стандартный вывод (STDOUT), могут работать некорректно, если вы запускаете программу из командной строки и используете ассоциацию файлов для запуска сценария.

person zoul    schedule 19.03.2010
comment
похоже проблема в этом. я нашел обходной путь, включающий передачу через файл bat, а затем вызов исполняемого файла perl (см. принятый ответ). Благодарность! - person Jenni; 19.03.2010
comment
+1 @zoul Я был так занят поиском информации, что не заметил, как ты уже разместил ссылку. - person Sinan Ünür; 19.03.2010

Нет ничего плохого в том, чтобы учиться на практике, но быстрый поиск в CPAN показывает ряд возможных решений проблемы tee в Perl.

Например: PerlIO::Tee.

person Telemachus    schedule 19.03.2010

Ну, ИМХО, Perl - плохая замена sed ;)

dir | sed s/2009/2010/

person Byron Whitlock    schedule 19.03.2010
comment
я упростил часть моего сценария, которая не имеет отношения к моему вопросу. - person Jenni; 19.03.2010
comment
Но perl — хорошая замена: 'sed' is not recognized as an internal or external command, operable program or batch file ;-) - person mob; 19.03.2010