Consider:
#!/usr/bin/perl
use strict;
use warnings;
my $command = "nosuchcommand"
my $rc = open( my $fh, "-|", "$command" );
if ( ! defined( $rc ) )
{
print "My own error message\n";
}
else
{
system( "ps -p $rc" );
}
Expected output:
My own error message
Observed output:
Can't exec "nosuchcommand": No such file or directory at ./mcre line 8.
My own error message
How can I catch / trap / suppress the error message generated by Perl on a failing open-pipe (in favor of my own error handling)?
Further observations:
If I open( my $fh, "-|", "$command 2>&1" );
, I get the expected output. But in case of success of $command
, I would get the STDERR
of $command
mixed into STDOUT
, and I don't want that.
If I open( my $fh, "-|", "$command 2>/dev/null" );
, I get this:
PID TTY TIME CMD
15143 pts/0 00:00:00 sh <defunct>
So the specific redirecion of 2>/dev/null
(instead of 2>&1
) changed the return value of open
... this was somewhat surprising, but is not the core of my question.
On IPC::Run
This has been suggested in two answers by now. I understand that it might be the "correct" answer in the general case, but would really prefer not to (as IPC::Run
is not an option for me on one very significant target platform that comes without it and does not offer an easy way to install it).
Can't exec "nosuchcommand": No such file or directory at ./mcre line 8.
This line is actually a "warning", enabled by use warnings;
. From perldiag:
Can't exec "%s": %s
(W exec) A system(), exec(), or piped open call could not execute the named program for the indicated reason. Typical reasons include: the permissions were wrong on the file, the file wasn't found in $ENV{PATH}, the executable in question was compiled for another architecture, or the #! line in a script points to an interpreter that can't be run for similar reasons. (Or maybe your system doesn't support #! at all.)
Now, use warnings;
is highly recommended, so just removing it entirely is not a "solution". But it is possible to disable warnings within a given scope via no warnings <category>
. So, to suppress that particular message:
#!/usr/bin/perl
use strict;
use warnings;
my $command = "nosuchcommand";
my @args = ();
my $rc;
my $fh;
{
no warnings qw( exec );
my $rc = open( my $fh, "-|", "$command", @args );
}
if ( ! defined( $rc ) )
{
print "My own error message: $!\n";
}
Output:
My own error message: No such file or directory
The part of the error message generated by the underlying shell ("No such file or directory") is in the $!
special variable. Note that you should be using the four-parameter version of open
(with an empty LIST if need be, as pictured above). Perl has different methods of executing external commands, one going through /bin/sh -c
(and not being under control of the exec
warning), and the other through execvp
(and being under control of said warning). The four-parameter version of open
ensures that Perl will use the latter.