在Linux中将STDERR重定向到Perl中的文件

问题描述 投票:0回答:1

因此,我试图使用Perl捕获运行一些基本Linux命令的错误消息。例如,我在运行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,该命令有效。

我该如何处理这个问题并解决它?

此外,我读了一些以前的线程,但没有找到任何相关的线程或方法来解决它。

linux perl stderr
1个回答
2
投票

将字符串插入到旨在作为单个参数的shell命令时,应始终使用String::ShellQuote来避免shell解析字符串中的非预期元字符(包括空格字符)的错误。它只实现了bourne shell引用,因此它可能与tcsh不兼容 - 但Perl通常配置为使用/ bin / sh,它应该与bourne shell兼容。

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

作为替代方案,您可以通过使用system()的列表形式并在Perl中重定向STDERR来完全避免shell。 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并避免shell,稍微更加手动。

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::RunIPC::Run3以获得更大的灵活性。

© www.soinside.com 2019 - 2024. All rights reserved.