How to execute an external script while capturing output and output code in Perl?

I am trying to verify the existence of SVN tags with a Perl script. So I'm trying to call svn info $url , read the exit code and suppress standard output and standard error streams. However, I try my best to do this (there are probably better ways to ask SVN about the tag, but this is not the point):

 my $output = `svn info $url/tags/$tag`; 

This suppresses the output by putting it in $output . The exit code is lost.

 my $output = `svn info $url/tags/$tag 2>&1`; 

This suppresses both STDERR and STDOUT and puts them in $output . The exit code is again lost.

 my $exitcode = system("svn", "info", "$url/tags/$tag"); 

This catches the exit code, but the actual stream of output and errors is displayed to the user.

 open( STDERR, q{>}, "/dev/null" ); open my $fh, q{>}, "/dev/null"; select($fh); if (system("svn", "info", "$url/tags/$tag") != 0) { select(STDOUT); print ("Tag doesn't exist!"); do_something_with_exit(); } select(STDOUT); print "Exit code: $exitcode"; 

This kills STDOUT and STDERR and catches the exit code, but it is ugly because I would have to remember to switch STDOUT back to the original.

So is there a more elegant solution?

+7
perl stdout stderr exit-code
source share
4 answers

Try using $? .eg

 my $output = `svn info $url/tags/$tag`; my $extcode = $?>>8; 
+8
source share

What happens when you try it using IPC :: System :: Simple ? This module handles most of the details of such problems:

  use IPC::System::Simple qw(capturex $EXITVAL); my $output = capturex( "some_command", @args ); my $exit = $EXITVAL; 
+3
source share
  my $output = `svn info $url/tags/$tag 2>&1`; 

This suppresses both STDERR and STDOUT and puts them in $ output. Exit code lost again

Are you sure the exit code is lost? When I try this, do I get the exit code in $? .

+1
source share

The IPC :: Run3 module provides very fine control over input and output.

 use IPC::Run3; run3 \@cmd, \$in, \$out, \$err; 

You can pass the same variable to \$out and \$err , and it will do what you expect by combining both streams. No input is needed, so you can pass either undef ("inherit from the parent process") or \undef ("private file descriptor".)

IPC::Run3::run3() returns true or false depending on the exit code and leaves the actual exit code of the child process in $? according to perlvar.

In your case, you run

 use IPC::Run3 my @cmd = ('svn', 'info', "$url/tags/$tag"); my $out; my $rv = run3(\@cmd, \undef, \$out, \$out); if ($rv) { # process $out } else { die "error: $@"; } 
0
source share

All Articles