views:

135

answers:

4

I'm trying to check for an SVN tag existence from a Perl script. So I try calling svn info $url, read exit code and suppress standard output and standard error streams. However, I struggle to do this elegantly (there are probably better ways to ask SVN about a tag, but that's not the point here):

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

This suppresses the output while putting it into $output. Exit code is lost.

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

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

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

This catches the exit code, but the actual output and error stream is visible 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 the STDOUT and STDERR and catches the exit code, but it's ugly because I'd have to remeber to switch the STDOUT back to original.

So, is there any more elegant solution?

+3  A: 

Try using $?.e.g.

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

bhups
The exit code is the high byte in `$?`, so you need `$?>> 8`.
brian d foy
@brian: thanks for pointing that out.
bhups
That was kinda a nudge for you to edit your answer. :)
brian d foy
Edited the answer... :)
bhups
+1  A: 
 my $output = `svn info $url/tags/$tag 2>&1`;

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

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

Hans W
Well, the exit code is the high byte in `$?`, so you need `$? >> 8`.
brian d foy
+3  A: 

What happens when you try it with IPC::System::Simple? That module handles most of the details of these sorts of problems:

 use IPC::System::Simple qw(capturex $EXITVAL);

 my $output = capturex( "some_command", @args );
 my $exit   = $EXITVAL;
brian d foy
A: 

The module IPC::Run3 gives very fine-grained control over the 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, combining both streams. The input is unnecessary, and so you can pass either undef ("inherit from parent process") or \undef ("closed filehandle".)

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

In your case you would 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: $@";
}
Kaoru
The return value from run3 only deals with its handling of the filehandles. It's meaningless for the exit code of the process.
brian d foy