I’m trying to wrap my head around IPC::Run to be able to do the following. For a list of files:
my @list = ('/my/file1.gz','/my/file2.gz','/my/file3.gz');
I want to execute a program that has built-in decompression, does some editing and filtering to them, and prints to stdout, giving some stats to stderr:
~/myprogram options $file
I want to append the stdout of the execution for all the files in the list to one single $out file, and be able to parse and store a couple of lines in each stderr as variables, while letting the rest be written out into separate fileN.log files for each input file.
I want stdout to all go into a “>>$all_into_one_single_out_file”, it’s the err that I want to keep in different logs.
After reading the manual, I’ve gone so far as to the code below, where the commented part I don’t know how to do:
for $file in @list {
my @cmd;
push @cmd, "~/myprogram options $file";
IPC::Run::run \@cmd, \undef, ">>$out",
sub {
my $foo .= $_[0];
#check if I want to keep my line, save value to $mylog1 or $mylog2
#let $foo and all the other lines be written into $file.log
};
}
Any ideas?
First things first.
my $foo .= $_[0]is not necessary.$foois a new (empty) value, so appending to it via.=doesn’t do anything. What you really want is a simplemy ($foo) = @_;.Next, you want to have output go to one specific file for each command while also (depending on some conditional) putting that same output to a common file.
Perl (among other languages) has a great facility to help in problems like this, and it is called closure. Whichever variables are in scope at the time of a subroutine definition, those variables are available for you to use.
Each of the output file handles will get closed when they’re no longer referenced by anything — in this case at the end of this snippet.
I fixed your
@cmd, though I don’t know what youroption1,option2, … will be.I also changed the way you are calling
run. You can call it with a simple>to tell it the next thing is for output, and thenew_chunker(from IPC::Run) will break your output into one-line-at-a-time instead of getting all the output all-at-once.I also skipped over the fact that you’re outputting to
.gzfiles. If you want to write to compressed files, instead of opening as:Just open up:
Be careful here as this is a good place for command injection (e.g. let
$filebe/dev/null; /sbin/reboot. How to handle this is given in many, many other places and is beyond the scope of what you’re actually asking.EDIT: re-read problem a bit more, and changed answer to more closely reflect the actual problem.EDIT2:: Updated per your comment. All stdout goes to one file, and the stderr from command is fed to the inline subroutine. Also fixed a stupid typo (for syntax was pseudo code not Perl).