tid has asked for the wisdom of the Perl Monks concerning the following question:

Greetings fellow monks,

I'm looking to capture both STDOUT and return value from a shell cmd (i.e. from something like system or backticks).

The actual application I'm trying to use is tar as a system call from within an time scheduled backup script, first to tar source control archives to tar file, and then to tar up a group of tar files directly onto tape for offsite backup. This is a common enough task that I'm surprised that I haven't been able to find any information.

I'm interested in the output of the tar application so that I can parse through it for specific pieces of information (like time jitter associated with using tar on windows filesystems mounted through samba). I also need to write the tar output to the scripts log file.

None of the usual suspects (camel book, ram book, panther book, or alpaca book) gave any useful information that I could find, so please be gentle if this one's a no-brainer.

Any help would be greatly appreciated,
Mike

  • Comment on Capturing return value and STDOUT from system like calls

Replies are listed 'Best First'.
Re: Capturing return value and STDOUT from system like calls
by BUU (Prior) on Apr 16, 2004 at 04:15 UTC
    my $stdout = `program`; my $return_value = $?;
      from system:
      $exit_value = $? >> 8; $signal_num = $? & 127; $dumped_core = $? & 128;
Re: Capturing return value and STDOUT from system like calls
by Zaxo (Archbishop) on Apr 16, 2004 at 04:39 UTC

    The --verbose list from tar appears on *STDERR. There are lots of ways to get at it, but here is a tidy way with PerlIO, perl 5.8+

    { open local(*STDERR), '>', \my $verbosity or die $!; my $status = system "/bin/tar -cv *.foo 1>$tarfile"; # parse $verbosity and log it }
    The use of a single string argument to system is not recommended, but for an archive/logging program that runs from cron there are few dangers. The single argument is desirable to invoke the shell to recognise output redirection and filename globbing.

    After Compline,
    Zaxo

Re: Capturing return value and STDOUT from system like calls
by Plankton (Vicar) on Apr 16, 2004 at 04:21 UTC
    Maybe something like this ...
    Plankton@linux:~/perl/perlmonks> cat opentar.pl #!/usr/bin/perl -w use strict; open TAR, "tar @ARGV|" or die "tar @ARGV" failed:$!\n"; my @stdout = <TAR>; print @stdout; close (TAR); Plankton@linux:~/perl/perlmonks> ./opentar.pl -cvf ../junk.tar . ./opentar.pl ./okaynow.pl ./SimpleType.pm ./coredump.pl

    Plankton: 1% Evil, 99% Hot Gas.
Re: Capturing return value and STDOUT from system like calls
by ctilmes (Vicar) on Apr 16, 2004 at 13:19 UTC
    Try IPC::Run. It has a nice interface for capturing STDOUT and STDERR.
Re: Capturing return value and STDOUT from system like calls
by zentara (Cardinal) on Apr 16, 2004 at 15:35 UTC
    IPC::Open3 is your best general purpose interface to run another program. Here are a couple of examples. The first is an interface to bc, which I toy with. The second is an example running tar.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use IO::Select; #interface to "bc" calculator my $pid = open3(\*WRITE, \*READ,\*ERROR,"bc"); #if \*ERROR is false, STDERR is sent to STDOUT my $selread = new IO::Select(); my $selerror = new IO::Select(); $selread->add(\*READ); $selerror->add(\*ERROR); # may not be best use of IO::Select, but it works :-) my($error,$answer)=('',''); while(1){ print "Enter expression for bc, i.e. 2 + 2\n"; chomp(my $query = <STDIN>); #send query to bc print WRITE "$query\n"; #timing delay needed tp let bc output select(undef,undef,undef,.01); #see which filehandles have output if($selread->can_read(0)){print "ready->read\n"} if($selerror->can_read(0)){print "ready->error\n"} #get any error from bc sysread(ERROR,$error,4096) if $selerror->can_read(0); if($error){print "\e[1;31m ERROR-> $error \e[0m \n"} #get the answer from bc sysread(READ,$answer,4096) if $selread->can_read(0); if($answer){print "$query = $answer\n"} ($error,$answer)=('',''); } waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created. __END__

    #################################################### #####################################################

    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use IO::Select; my $pid = open3(\*WRITE, \*READ,\*ERROR,"tar -zcvf mytar.tgz *"); #try this for an error #my $pid = open3(\*WRITE, \*READ,\*ERROR,"tar -zcvf mytar.tgz ^*"); #if \*ERROR is false, STDERR is sent to STDOUT my $selread = new IO::Select(); my $selerror = new IO::Select(); $selread->add(\*READ); $selerror->add(\*ERROR); # may not be best use of IO::Select, but it works :-) my($error,$answer)=('',''); #timing delay needed tp let tar output select(undef,undef,undef,.01); #see which filehandles have output if($selread->can_read(0)){print "ready->read\n"} if($selerror->can_read(0)){print "ready->error\n"} #get any error from tar sysread(ERROR,$error,4096) if $selerror->can_read(0); if($error){print "\e[1;31m ERROR-> $error \e[0m \n"} #get the output from tar sysread(READ,$answer,4096) if $selread->can_read(0); if($answer){print "$answer\n"} waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created. __END__

    I'm not really a human, but I play one on earth. flash japh