如何使用 su -c 从在管道中执行的命令中获取 Perl 中的 STDERR
How to get STDERR in Perl from a command executed in pipe with su -c
我正在尝试使用以下方法捕获以不同用户身份执行的命令的输出:
my $command = qq(sudo su - <username> -c '/usr/bin/whatever');
my $pid = open $cmdOutput, "-|", $command;
如何捕获 /usr/bin/whatever
的 STDERR?
我试过了
$pid = open $cmdOutput, "-|", $command || die " something went wrong: $!";
但看起来这是在捕获 "open" 本身可能的错误。
我也试过了
my $command = qq(sudo su - <username> -c '/usr/bin/whatever' 2>/tmp/error.message);
这会将 STDERR 重定向到我稍后可以解析的文件,但我想要一些更直接的解决方案。
另外,我只想使用核心模块。
in perlfaq8. Since you are using a piped open, the relevant examples are those that go by open3
from the core IPC::Open3 模块涵盖得很透彻。
另一种选择是使用 IPC::Run 来管理您的进程,pump
函数将满足您的需要。 IPC::Open3
文档说 IPC::Run
This is a CPAN module that has better error handling and more facilities than Open3.
使用其中任何一个,您都可以根据需要单独或一起操作 STDOUT
和 STDERR
。为了方便和完整的输出捕获,另请参阅 Capture::Tiny.
除了 2>output
重定向之外,没有更多用于管道打开的基本方法。
如果您不介意混合流或完全丢失 STDOUT
,另一种选择是
my $command = 'cmd 2>&1 1>/dev/null' # Remove 1>/dev/null to have both
my $pid = open my $cmdOutput, "-|", $command;
while (<$cmdOutput>) { print } # STDERR only
第一个重定向将 STDERR
流与 STDOUT
合并,因此您可以同时获得它们并混合(STDOUT
受缓冲影响,因此事情很可能会出现混乱)。第二个重定向将 STDOUT
发送出去,因此您只从句柄中读取命令的 STDERR
。
问题是关于 运行 使用 open
的外部命令,但我想提一下规范和简单的 qx (backticks) 可以用同样的方式使用。它 returns STDOUT
因此需要像上面那样重定向才能获得 STDERR
。为了完整性:
my $cmd = 'cmd_to_execute';
my $allout = qx($cmd 2>&1); # Both STDOUT and STDERR in $out, or
my $stderr = qx($cmd 2>&1 1>/dev/null); # Only STDERR
my $exit_status = $?;
qx
将子进程退出代码(状态)放入 $?
。然后可以检查故障模式;请参阅 qx
页面中的摘要或 I/O operators in perlop.
中的非常详尽的讨论
请注意,以这种方式返回的 STDERR
是 来自命令 ,如果它 运行。如果命令本身不能是 运行(因为命令名称中的拼写错误,或者 fork
由于某种原因失败)那么 $?
将是 -1
并且错误将是在 $!
.
所需的目的地,打开写入,可以 dup()'ed 到 FD #2
根据 zdim 的建议,我使用了 IPC::Open3 模块来解决这个问题,我有类似的东西可以帮我完成这项工作
$instanceCommand = qq(sudo su - <username> -c '<command>');
my ($infh,$outfh,$errfh,$pid);
$errfh = gensym();
$pid = open3($infh, $outfh, $errfh, $instanceCommand);
my $sel = new IO::Select;
$sel->add($outfh,$errfh);
while (my @ready = $sel->can_read){
foreach my $fh (@ready){
my $line =<$fh>;
if (not defined $line){
$sel->remove($fh);
next;
}
if ($fh == $outfh){
chomp($line);
#<----- command output processing ----->
}
elsif ($fh == $errfh){
chomp $line;
#<----- command error processing ----->
}
else {
die "Reading from something else\n";
}
}
}
waitpid($pid, 0);
也许不是完全防弹,但它对我来说工作得很好。即使在执行有趣的级联脚本时也是 < command > .
我正在尝试使用以下方法捕获以不同用户身份执行的命令的输出:
my $command = qq(sudo su - <username> -c '/usr/bin/whatever');
my $pid = open $cmdOutput, "-|", $command;
如何捕获 /usr/bin/whatever
的 STDERR?
我试过了
$pid = open $cmdOutput, "-|", $command || die " something went wrong: $!";
但看起来这是在捕获 "open" 本身可能的错误。
我也试过了
my $command = qq(sudo su - <username> -c '/usr/bin/whatever' 2>/tmp/error.message);
这会将 STDERR 重定向到我稍后可以解析的文件,但我想要一些更直接的解决方案。
另外,我只想使用核心模块。
in perlfaq8. Since you are using a piped open, the relevant examples are those that go by open3
from the core IPC::Open3 模块涵盖得很透彻。
另一种选择是使用 IPC::Run 来管理您的进程,pump
函数将满足您的需要。 IPC::Open3
文档说 IPC::Run
This is a CPAN module that has better error handling and more facilities than Open3.
使用其中任何一个,您都可以根据需要单独或一起操作 STDOUT
和 STDERR
。为了方便和完整的输出捕获,另请参阅 Capture::Tiny.
除了 2>output
重定向之外,没有更多用于管道打开的基本方法。
如果您不介意混合流或完全丢失 STDOUT
,另一种选择是
my $command = 'cmd 2>&1 1>/dev/null' # Remove 1>/dev/null to have both
my $pid = open my $cmdOutput, "-|", $command;
while (<$cmdOutput>) { print } # STDERR only
第一个重定向将 STDERR
流与 STDOUT
合并,因此您可以同时获得它们并混合(STDOUT
受缓冲影响,因此事情很可能会出现混乱)。第二个重定向将 STDOUT
发送出去,因此您只从句柄中读取命令的 STDERR
。
问题是关于 运行 使用 open
的外部命令,但我想提一下规范和简单的 qx (backticks) 可以用同样的方式使用。它 returns STDOUT
因此需要像上面那样重定向才能获得 STDERR
。为了完整性:
my $cmd = 'cmd_to_execute';
my $allout = qx($cmd 2>&1); # Both STDOUT and STDERR in $out, or
my $stderr = qx($cmd 2>&1 1>/dev/null); # Only STDERR
my $exit_status = $?;
qx
将子进程退出代码(状态)放入 $?
。然后可以检查故障模式;请参阅 qx
页面中的摘要或 I/O operators in perlop.
请注意,以这种方式返回的 STDERR
是 来自命令 ,如果它 运行。如果命令本身不能是 运行(因为命令名称中的拼写错误,或者 fork
由于某种原因失败)那么 $?
将是 -1
并且错误将是在 $!
.
所需的目的地,打开写入,可以 dup()'ed 到 FD #2
根据 zdim 的建议,我使用了 IPC::Open3 模块来解决这个问题,我有类似的东西可以帮我完成这项工作
$instanceCommand = qq(sudo su - <username> -c '<command>');
my ($infh,$outfh,$errfh,$pid);
$errfh = gensym();
$pid = open3($infh, $outfh, $errfh, $instanceCommand);
my $sel = new IO::Select;
$sel->add($outfh,$errfh);
while (my @ready = $sel->can_read){
foreach my $fh (@ready){
my $line =<$fh>;
if (not defined $line){
$sel->remove($fh);
next;
}
if ($fh == $outfh){
chomp($line);
#<----- command output processing ----->
}
elsif ($fh == $errfh){
chomp $line;
#<----- command error processing ----->
}
else {
die "Reading from something else\n";
}
}
}
waitpid($pid, 0);
也许不是完全防弹,但它对我来说工作得很好。即使在执行有趣的级联脚本时也是 < command > .