Capturing system command output in perl

Running system commands from inside a perl script is one of the nastiest of all perl headaches. I suffered grievously when trying to use this method with some pdf file addons, and have scars to show for it. Lately, having failed to learn my lesson not to mess with this stuff, I have been working on something similar: trying to use the new version of 7-zip to get crc hashes for the excel files in a directory.

The idea is to use the hash checksums to see which files have been modified, compared to an earlier archived version of the files. 7-zip command line syntax is already tricky and I have no idea what I’m doing in most of this; I’m just following incantations found on various occult internet sites. Here is the command line version of the 7-zip command:

"c:\Program Files\7-zip\7za.exe" h -ir!d:\foo\*.xls -ir!d:\foo\*.xlsx > temp.txt

This gets the crc hashes for all the xls and xlsx files in the d drive directory foo. Doing this in a perl script is equally tricky; the key is putting the various segments into an array, as follows:

my @cmds = (
'c:\Program Files\7-Zip\7za.exe', 'h',
'-ir!d:\foo\*.xls',
'-ir!d:\foo\*.xlsx'
);

One then uses system to invoke the mystic phrases, and an ‘or’ clause to ask for an explanation if it fails:

system (@cmds) == 0
or die "system @cmds failed: $?\n";

The procedure described above works, but the mind boggling issue is how to get the output of this command (lengthy scrolling for about 20 seconds) into a perl variable where you can do something with it. This task completely defeated me after half a day. I then switched to trying to pipe the output into a file. This accounted for the second half of my day. In fact, there is a ready made solution to this problem: Capture::Tiny, written by David Golden and included in the ActivePerl distribution.

The final result is:

use Capture::Tiny ':all';
my ($stdout, $stderr, $exit) = capture {
system( @cmds );
};

The output of the system call is in $stdout, the error info is in $stderr, and the exit return code is in $exit.

All hail David Golden! Hail!!

This entry was posted in Programming. Bookmark the permalink.