use IPC::Run qw(run);
run(["cat", "/etc/passwd"], "|",
["egrep", "-v", ':/bin/bash$'], "|",
["wc", "-l"],
undef, \$out);
print $out;
Not the best way to do that sort of thing (useless use of cat for instance), I was just trying to come up with an executable example. run returns success or failure of the pipeline as the return code, which I don't show here. I don't think you can pick out which command failed.
I also find that once you're in a real programming language, you have much less need to have deep pipelines anyhow. Consider the pure-perl equivalent
open PW, "<", "/etc/passwd" or die;
while (<PW>) {
next if $_ =~ m|:/bin/bash$|;
$count++;
}
print "$count\n";
Of course "real perl" would suggest some form of "use strict" and the corresponding need to declare the $count var, but if we're discussing shell script contexts it is at least fair to consider ignoring that, since it would be a silly objection that the perl equivalent doesn't turn on checks that shell scripting doesn't even have.
But if you're in a real programming language you don't need to shell out to wc just to get a line count, or write complicated awk scripts, etc. It's much more common for me in those cases to execute a single program and control its STDIN/STDOUT/STDERR and watch its exit code.