Все задачи

Что-что вы сказали? Часть 2

30 Aug 2013

Программист учел проблемы в предыдущей версии функции exec_and_get_output (см. историю Что-что вы сказали?). Он решил все переделать и воспользоваться функцией open с тремя аргументами.

Вот новая версия:

# выполняет внешнюю программу, 
# возвращает ее stdout в виде массива строк или одной строки в зависимости от контекста вызова.
# Если программу не удалось выполнить или она закончилась ошибкой -- умирает.

sub exec_and_get_output
{
   my @cmd  = @_;

   open( my $FH_OUT, '-|', @cmd ) or die "Can't exec[@cmd]: $? $!";
   my @answer = <$FH_OUT>;

   if (wantarray) {
       chomp for @answer;
       return @answer;
   } else {
       return join '', @answer;
   }
}

И что бы вы думали? Теперь функция не умирает в некоторых случаях, когда должна.

Пример кода можно скачать.

Подсказка

Показать

Например, если выполнить exec_and_get_output('false'), функция не умрет, хотя должна бы.

man false

Подсказка-2

Показать

И вообще функция не умирает, если внешняя программа запускается, но завершается с ненулевым кодом.

Подсказка-3

Показать

Цитата из perldoc -f open:

if MODE is "-|", the filename is interpreted as a command that pipes output to us.  
... See "Using open() for IPC" in perlipc for more examples of this.

То есть: читайте секцию “Использование open() для межпроцессного взаимодействия” в разделе справки perlipc.

Разоблачение

Показать

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

Для того, чтобы получить и проверить код завершения внешней программы, следует закрыть (close) соответствующий файл-хендлер:

   open( my $FH_OUT, '-|', @cmd ) or die "Can't exec[@cmd]: $? $!";
   my @answer = <$FH_OUT>;
+   close($FH_OUT) or die "Non-zero exit status [@cmd]: $?";

   if (wantarray) {
   ...