Как я могу запустить внешнюю команду и записать ее вывод в Perl? - PullRequest
18 голосов
/ 17 марта 2010

Я новичок в Perl и хочу знать способ запуска внешней команды (назовите ее prg) в следующих сценариях:

  1. Запустите prg, получите только stdout.
  2. Запустите prg, получите только stderr.
  3. Запустите prg, получите его stdout и stderr, отдельно.

Ответы [ 4 ]

27 голосов
/ 17 марта 2010

Вы можете использовать backtics для запуска вашей внешней программы и захвата ее stdout и stderr.

По умолчанию обратные метки отбрасывают stderr и возвращают только stdout внешней программы. Поэтому

$output = `cmd`;

Захватит stdout программы cmd и сбросит stderr.

Для захвата только stderr вы можете использовать файловые дескрипторы оболочки как:

$output = `cmd 2>&1 1>/dev/null`;

Для захвата stdout и stderr вы можете сделать:

$output = `cmd 2>&1`;

Используя вышеописанное, вы не сможете отличить stderr от stdout. Для разделения stdout от stderr можно перенаправить как в отдельный файл, так и прочитать файлы:

`cmd 1>stdout.txt 2>stderr.txt`;
10 голосов
/ 17 марта 2010

Вы можете использовать IPC :: Open3 или IPC :: Run .Также прочитайте Как мне захватить STDERR из внешней команды из perlfaq8 .

8 голосов
/ 17 марта 2010

В большинстве случаев вы можете использовать оператор qx// (или обратные галочки). Он интерполирует строки и выполняет их с оболочкой, поэтому вы можете использовать перенаправления.

  • Чтобы зафиксировать STDOUT команды (STDERR не затрагивается):

    $output = `cmd`;
    
  • Чтобы захватить STDERR и STDOUT команды вместе:

    $output = `cmd 2>&1`;
    
  • Чтобы захватить STDERR команды, но отбросить ее STDOUT (здесь важен порядок):

    $output = `cmd 2>&1 1>/dev/null`;
    
  • Чтобы заменить STDOUT команды и STDERR, чтобы захватить STDERR, но оставить STDOUT, чтобы выйти из старого STDERR:

    $output = `cmd 3>&1 1>&2 2>&3 3>&-`;
    
  • Чтобы прочитать STDOUT команды и ее STDERR по отдельности, проще всего перенаправить их отдельно в файлы, а затем прочитать из этих файлов, когда программа будет завершена:

    system("program args 1>program.stdout 2>program.stderr");
    
1 голос
/ 13 марта 2019

Остерегайтесь ответа Юджина (не могу прокомментировать его ответ), чуть выше, что синтаксис для обмена SDTOUT и STDERR действует в Unix (Unixen-подобных оболочках, таких как ksh или bash, я думаю), но не под Windows CMD (ошибка: 3>& was unexpected at this time.).

Подходящий синтаксис в Windows CMD и Perl в Windows:

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2};

Обратите внимание, что команда:

nslookup 255.255.255.255

будет производить (что-то вроде) на STDOUT:

Server:  mymodem.lan
Address:  fd37:c01e:a880::1

и на STDERR:

*** mymodem.lan can't find 255.255.255.255: Non-existent domain

Вы можете проверить, что этот синтаксис работает со следующим синтаксисом CMD / Perl:

Первый:

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print qq{on STDOUT qx result=[$r]};"

вы получите: Server: mymodem.lan Address: fd37:c01e:a880::1 on STDOUT qx result=[*** mymodem.lan can't find 255.255.255.255: Non-existent domain]

Тогда

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print STDOUT qq{on STDOUT qx result=[$r]};" 2>&1 1>NUL:

вы получите: Server: mymodem.lan Address: fd37:c01e:a880::1

QED [fr: CQFD]

Обратите внимание, что невозможно получить ОБА stderr и stdout в качестве возвращаемой строки для команды qx или backticks. Если вы точно знаете, что текст ошибки, возвращаемый вашей порожденной командой, имеет длину N строк, вы все равно можете перенаправить STDERR в STDOUT, как описано Евгением и другими, но записать ваш возвращенный текст qx в массив, а не в виде скалярной строки. Поток STDERR будет возвращен в массив до STDOUT, так что N первых строк вашего массива будут строками SDTERR. Как:

@r=qx{nslookup 255.255.255.255 2>&1};
$r[0] is "*** mymodem.lan can't find 255.255.255.255: Non-existent domain"

Но, конечно, вы должны быть уверены, что - это текст ошибки в STDERR и строго N строк (хранится в @r[0..N-1]). Если нет, то единственным решением является использование временных файлов, как описано выше.

...