I'll do a first pass where I point out syntax and Perl conventions, mostly line by line. I will then talk about alternative strategies to make it more efficient and maintainable.
#Syntax
die "$message\n";
If you include a trailing newline "\n" in your message to die, it will not tell you what line it died on. You are mixing both versions. I think you should stick with the line numbers. Get rid of the newline.
run_parallel(
[
[
'tmp1', # directory
'echo "ave Maria" > aveMaria.txt', #command
],
[
'tmp2', # directory
'echo "IN HOC SIGNO VINCES" > xp.txt', #command
],
]
);
#Maintainability
You have some code duplication in the signal handler and execute. Opening and writing the file is implemented twice, with only the same error message being different. It would be nicer to write a function that does all of that, and pass it the message. You can then use that function in the signal handler as well as execute.
There is also no need to explicitly close, as $fh is lexical and will be cleaned up automatically when it goes out of scope, or in this case, the program ends.
sub log_error_and_die {
my $error = shift;
my $fail_filename = "$TOP_DIRECTORY/$0.FAIL";
open my $fh, '>', $fail_filename or die "Can't write $fail_filename: $!";
print $fh $error;
die $error;
}
And you can call it like this
# kill the program if there are any warnings
local $SIG{__WARN__} = sub {
my $message = shift;
log_error_and_die( sprintf( '%s @ %s', $message, getcwd() ) );
};
and
sub execute {
my $command = shift;
print "Executing Command: $command\n";
if (system($command) != 0) {
log_error_and_die("$command failed.");
}
}
Why are there always four jobs? If there are a lot of files, wouldn't it be easier to make this an option? Especially with your limited input data, four jobs are overkill. But they might be not enough.
I would add a second argument to run_parallel and pass the number of parallel jobs.
sub run_parallel {
my ($commands, $jobs) = @_; # alternate way to get arguments
# ...
my $manager = Parallel::ForkManager($jobs);
}
Of course, since there is nothing else, you can also get rid of that function all together. If you only ever call it once from the body of your script, I believe there's no need to make it into a function. Opinions vary on this, though.