2008-09-16 3 views
3

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

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

ответ

3

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

use IPC::Open2; 

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

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

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

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

+1

Для всех, кто это читает, вы должны убедиться, что не используете дескрипторы дескрипторов в этом примере. См. Этот документ: http://www.perlfoundation.org/perl5/index.cgi?bareword_uppercase_filehandles – 2008-09-17 03:14:05

0

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

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(); 
    } 
} 
+0

Я не вижу, где ваш пример обрабатывает STDIN. – 2010-11-08 18:52:41

3

perlipc documentation охватывает множество способов, которые вы можете сделать это, в том числе IPC :: open2 и IPC :: open3.

6

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

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

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

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

0

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

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

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

2

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

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

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

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

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

  • Нет связанных вопросов^_^