taiko taiko - 1 year ago 63
Perl Question

PERL - How to get STDERR from command executed in pipe with su -c

I'm trying to capture the output of the command executed as different user using

my $command = qq(sudo su - <username> -c '/usr/bin/whatever');
my $pid = open $cmdOutput, "-|", $command;

How can I capture the STDERR of /usr/bin/whatever ?

I tried

$pid = open $cmdOutput, "-|", $command || die " something went wrong: $!";

but it looks like this is capturing the possible errors of "open" itself.

I also tried

my $command = qq(sudo su - <username> -c '/usr/bin/whatever' 2>/tmp/error.message);

which will redirect the STDERR to the file, which I can parse later, but I wanted some more straightforward solution.
Also I only want to use core modules.

Answer Source

This is reviewed thoroughly in perlfaq8. Since you are using a piped open most of the relevant examples go by open3 from the core IPC::Open3 module.

Another option is to use IPC::Run for your ipc, and the pump function will do what you need. The IPC::Open3 documentation says for IPC::Run

This is a CPAN module that has better error handling and more facilities than Open3.

With both you can manipulate STDOUT and STDERR separately or together, as needed.

Other than 2>output redirection there are no more elementary methods for the piped open.

Another option, which either mixes streams or loses STDOUT altogether, is

my $command = 'cmd 2>&1 1>/dev/null;'
my $pid = open my $cmdOutput, "-|", $command;

while (<$cmdOutput>) { print }

The first redirection merges STDERR stream with STDOUT so you would get them both, and mixed (with STDOUT subject to buffering). The second redirect sends the STDOUT away so with it you are reading only the command's STDERR from the handle.