Как я могу захватить stdin и stdout системной команды из сценария Perl? - PullRequest
3 голосов
/ 17 сентября 2008

В середине скрипта Perl находится системная команда, которую я хочу выполнить. У меня есть строка, содержащая данные, которые должны быть введены в стандартный ввод (команда принимает входные данные только из стандартного ввода), и мне нужно захватить вывод, записанный в стандартный вывод. Я рассмотрел различные методы выполнения системных команд в Perl, и мне кажется, что мне нужна именно функция open, за исключением того, что, похоже, я могу захватывать только стандартный ввод или стандартный вывод, а не оба.

На данный момент кажется, что мое лучшее решение - использовать open, перенаправить стандартный вывод во временный файл и читать из файла после завершения команды. Есть ли лучшее решение?

Ответы [ 9 ]

6 голосов
/ 17 сентября 2008

IPC :: Open2 / 3 в порядке, но я обнаружил, что обычно все, что мне действительно нужно, это IPC :: Run3 , который действительно хорошо справляется с простыми случаями с минимальной сложностью:

use IPC::Run3;    # Exports run3() by default

run3( \@cmd, \$in, \$out, \$err );

Документация сравнивает IPC :: Run3 с другими альтернативами. Это стоит прочитать, даже если вы не решите его использовать.

3 голосов
/ 17 сентября 2008

Документация perlipc охватывает множество способов сделать это, включая IPC :: Open2 и IPC :: Open3.

3 голосов
/ 17 сентября 2008

Где-нибудь вверху вашего скрипта, включите строку

use IPC::Open2;

Это будет включать необходимый модуль, обычно устанавливаемый с большинством дистрибутивов Perl по умолчанию. (Если у вас его нет, вы можете установить его с помощью CPAN.) Затем вместо open, позвоните:

$pid = open2($cmd_out, $cmd_in, 'some cmd and args');

Вы можете отправить данные своей команде, отправив ее в $ cmd_in, а затем прочитать вывод своей команды, прочитав из $ cmd_out.

Если вы также хотите иметь возможность читать поток команды stderr, вы можете вместо этого использовать модуль IPC :: Open3.

3 голосов
/ 17 сентября 2008

IPC :: Open3, вероятно, будет делать то, что вы хотите. Может захватывать STDERR и STDOUT.

http://metacpan.org/pod/IPC::Open3

2 голосов
/ 17 сентября 2008

Недавно я нашел очень простой способ сделать это: IPC :: Filter module . Это позволяет выполнять работу чрезвычайно интуитивно:

$output = filter $input, 'somecmd', '--with', 'various=args', '--etc';

Обратите внимание, как она вызывает вашу команду, не проходя через оболочку, если вы передаете ей список. Это также делает разумную работу по обработке ошибок для общих утилит. (В случае ошибки он die s использует текст из STDERR в качестве сообщения об ошибке; в случае успеха STDERR просто отбрасывается.)

Конечно, он не подходит для огромных объемов данных, поскольку он не обеспечивает никакой потоковой обработки; Кроме того, обработка ошибок может быть недостаточно детальной для ваших нужд. Но это делает многие простые случаи действительно действительно простыми.

1 голос
/ 17 сентября 2008

Для него есть специальная команда perl

open2()

Более подробную информацию можно найти на: http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html

1 голос
/ 17 сентября 2008

Я думаю, вы хотите взглянуть на IPC :: Open2

0 голосов
/ 17 сентября 2008

Если вы не хотите включать дополнительные пакеты, вы можете просто сделать

open(TMP,">tmpfile");
print TMP  $tmpdata ;
open(RES,"$yourcommand|");
$res = "" ;
while(<RES>){
$res .= $_ ;
}

что противоречит тому, что вы предложили, но также должно работать.

0 голосов
/ 17 сентября 2008

Я всегда делаю это таким образом, если я ожидаю только одну строку вывода или хочу разделить результат на что-то, кроме новой строки:

my $result = qx( command args 2>&1 );  
my $rc=$?;  
# $rc >> 8 is the exit code of the called program.

if ($rc != 0 ) {  
    error();  
}  

Если вы хотите иметь дело с многострочным ответом, получите результат в виде массива:

my @lines = qx( command args 2>&1 );  

foreach ( my $line ) (@lines) {  
    if ( $line =~ /some pattern/ ) {  
        do_something();  
    }  
}  
...