Как я могу захватить stdin и stdout системной команды из сценария Perl?

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

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


person Community    schedule 16.09.2008    source источник


Ответы (9)


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

person Leon Timmermans    schedule 16.09.2008

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

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

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

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

person xdg    schedule 17.09.2008

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

person brian d foy    schedule 17.09.2008

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

use IPC::Open2;

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

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

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

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

person benzado    schedule 16.09.2008
comment
Для всех, кто читает это, вы должны убедиться, что не использовать файловые дескрипторы, как в этом примере. См. Этот документ: perlfoundation.org/perl5/ - person Brian Phillips; 17.09.2008

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

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

person mopoke    schedule 16.09.2008

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

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

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

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

person Aristotle Pagaltzis    schedule 17.09.2008

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

open2()

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

person X-Istence    schedule 16.09.2008
comment
Чувак, а зачем ты выкладываешь то, что уже было опубликовано? - person Leon Timmermans; 17.09.2008

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

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

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

person stephanea    schedule 17.09.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();  
    }  
}  
person Community    schedule 16.09.2008
comment
я не вижу, где ваш пример обрабатывает STDIN. - person jm.; 08.11.2010