sub output_of {
my(@commands) = @_;
my $pid = open my $fh, "-|" // die "$0: fork: $!";
return $fh if $pid;
for (@commands) {
my $grandchild = open my $gfh, "-|" // die "$0: fork: $!";
if ($grandchild) {
print while <$gfh>;
close $gfh or warn "$0: close: $!";
}
else {
exec @$_ or die "$0: exec @$_: $!";
}
}
exit 0; # child
}
Call it as with my $fh = output_of [qw( echo -- )],
[qw( ls / )],
[qw( echo -- )];
while (<$fh>) {
print "got: $_";
}
close $fh or warn "$0: close: $!";
If implicitly using the shell is acceptable, but we want to interpose some processing, that will resemble my $output = `echo -- ; ls / ; echo --` // die "$0: command failed";
chomp $output;
print "$0: lines = ", `echo '$output' | wc -l`;
This becomes problematic if the output from earlier commands collides with the shell’s quoting rules. This lack of “manipulexity” that we quickly bump into with shell scripts — that are otherwise great on the “whipuptitude” axis — was a common frustration before Perl. The gap between C and the shell is exactly the niche on POSIX systems that Perl occupies and was its initial motivation.If all you want to do is redirect anyway, run
system("{ echo -- ; ls / ; echo -- ; } > out.txt") == 0
or die "$0: command failed";
Use the appropriate tool for the job. Perl was not designed to replace the shell but to build upon it. The shell is great for small programs with linear control flow. It’s hard to beat the shell for do-this-then-this processing. The real world likes to get more complex and nuanced and inconsistent, however.Maybe I am missing your point entirely. Do you have a more concrete example in mind?