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

在Linux中将STDERR重定向到来自Perl的文件,linux,perl,stderr,Linux,Perl,Stderr,因此,我试图通过使用Perl运行一些基本的Linux命令来捕获错误消息。例如,在运行ldd命令时,我尝试捕获STDERR: # The stderr_file already exists my $cmd = "ldd $file 2>$stderr_file"; my $output = `$cmd`; 但是,即使ldd命令的输出确实包含错误消息,例如ldd:warning:您没有执行的权限,它也不会将它们打印到$stderr\u文件中,我想知道为什么 然后我尝试自己运行命令:ldd/

因此,我试图通过使用Perl运行一些基本的Linux命令来捕获错误消息。例如,在运行
ldd
命令时,我尝试捕获
STDERR

# The stderr_file already exists
my $cmd = "ldd $file 2>$stderr_file";
my $output = `$cmd`;
但是,即使
ldd
命令的输出确实包含错误消息,例如
ldd:warning:您没有执行
的权限,它也不会将它们打印到
$stderr\u文件中,我想知道为什么

然后我尝试自己运行命令:
ldd/some/path/to/file 2>/error.log
,但失败的原因是:
ldd:./2:没有这样的文件或目录

我怀疑原因是因为我的Linux使用了
Tcsh
,因为如果我切换到
Bash
,命令就会工作

我应该如何处理和解决这个问题


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

当将字符串插入到打算作为单参数的shell命令中时,您应该始终使用,以避免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。这很容易

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或通过适当的错误检查打开文件并自己写入。)

核心模块还可以用于单独捕获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,而不是如上所述,或者为了更大的灵活性。

当将字符串插入到打算作为单参数的shell命令中时,您应该始终使用,以避免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。这很容易

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或通过适当的错误检查打开文件并自己写入。)

核心模块还可以用于单独捕获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,而不是如上所述,或者为了更大的灵活性。

Backticks倾向于在Linux中运行
/bin/sh
,而不是
tcsh
。选中
perl-MConfig-wle'print$Config{sh}
。反勾号倾向于在Linux中运行
/bin/sh
,而不是
tcsh
。检查
perl-MConfig-wle'print$Config{sh}'
。据我所知,如果没有任何额外的模块,就没有办法做到这一点?@TTaJTa4这当然是可能的(通过执行与Capture::Tiny相同的操作),但它相当脏。我将添加一个使用IPC::Open3的示例,这是一个核心模块,但仍然比使用Capture::Tiny更难看。我想我将尝试这些模块,但您能否添加一个示例,演示如何在没有任何模块的情况下完成(为了教育:)?即使没有核心module@TTaJTa4如果不使用您现有的核心模块,我看不到重新实现它的意义,但是Capture::Tiny和IPC::Open3的源代码是免费的。您的IPC::Open3代码有缺陷。如果子级向其STDERR输出足够的量,它将死锁。改用IPC::Run或IPC::Run3。据我所知,如果没有任何额外的模块,就没有办法做到这一点?@TTaJTa4这当然是可能的(通过执行Capture::Tiny所做的相同操作),但它相当脏。我将添加一个使用IPC::Open3的示例,这是一个核心模块,但仍然比使用Capture::Tiny更难看。我想我将尝试这些模块,但您能否添加一个示例,演示如何在没有任何模块的情况下完成(为了教育:)?即使没有核心module@TTaJTa4如果不使用您现有的核心模块,我看不到重新实现它的意义,但是Capture::Tiny和IPC::Open3的源代码是免费的。您的IPC::Open3代码有缺陷。如果子级向其STDERR输出足够的量,它将死锁。改用IPC::Run或IPC::Run3。