Перенаправить STDERR в файл из Perl в Linux - PullRequest
0 голосов
/ 19 февраля 2019

Итак, я пытался перехватить сообщения об ошибках при запуске какой-то базовой команды Linux с использованием Perl.Например, я пытаюсь перехватить STDERR при выполнении команды ldd:

# The stderr_file already exists
my $cmd = "ldd $file 2>$stderr_file";
my $output = `$cmd`;

Но даже если выходные данные команды ldd содержат сообщения об ошибках, такие как ldd: warning: you do not have execution permission for,он не будет печатать их в $stderr_file, и я удивляюсь, почему.

Затем я попытался выполнить команду сам: ldd /some/path/to/file 2>./error.log, и она завершилась неудачно: ldd: ./2: No such file or directory.

Я подозреваю, что причина в том, что мой Linux использует Tcsh, потому что, если я переключаюсь на Bash, команда работает.

Как мне подойти к этой проблеме и решить ее?

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

1 Ответ

0 голосов
/ 19 февраля 2019

При интерполяции строк в команды оболочки, которые предназначены для одиночных аргументов, вы всегда должны использовать String :: ShellQuote , чтобы избежать ошибок, когда оболочка анализирует непреднамеренные метасимволы в ваших строках (включая пробелы).Однако он реализует только цитирование оболочки Bourne, поэтому он также может быть несовместим с tcsh - но Perl обычно настраивается на использование / bin / sh, который должен быть совместимым с оболочкой Bourne.

use strict;
use warnings;
use String::ShellQuote;
my $cmd = 'ldd ' . shell_quote($file) . ' 2>' . shell_quote($stderr_file);

В качестве альтернативы,Вы можете полностью избежать оболочки, используя форму списка system () и перенаправляя STDERR в Perl. Capture :: Tiny делает это простым.

use strict;
use warnings;
use Capture::Tiny 'capture';
use Path::Tiny;
my ($out, $err, $exit_code) = capture { system 'ldd', $file };
# error checking for system() call here
path($stderr_file)->spew_raw($err);

(Path :: Tiny - только пример, вы также можете использовать File :: Slurper или открыть файл и написать в него самостоятельнос соответствующей проверкой ошибок.)

Основной модуль IPC :: Open3 также может использоваться для захвата STDERR отдельно и для обхода оболочки, несколько более вручную.

use strict;
use warnings;
use IPC::Open3;
use Symbol 'gensym';
my $pid = open3 undef, my $stdout, my $stderr = gensym, 'ldd', $file;
my ($out, $err);
{
  local $/;
  $out = readline $stdout;
  $err = readline $stderr;
}
waitpid $pid, 0;
my $exit_code = $? >> 8;

Это может привести к тупикам, если процесс выводит достаточное количество для STDERR.Я настоятельно рекомендую использовать Capture :: Tiny вместо описанного выше, или IPC :: Run или IPC :: Run3 для большей гибкости.

...