Firstly, there is something suspicious in the code you are showing: are you getting the value $? before the actual launch of the command. I will now discuss what I think you wanted to write:
my $command = "cd $STEPBYSTEP_HOME/collins-parser;" . "cat models/model$model_num/events | code/parser $src models/model$model_num/grammar 10000 1 1 1 1 1> $dest 2> $parse_log"; my $ret_val = `$command`; my $ret_code = $?;
After that, $ret_code contains the status of the entire shell command. This, in turn, is the status of the last team on the list, which is the cat ... | code/parser ... pipeline cat ... | code/parser ... cat ... | code/parser ... Depending on the shell, this can be either the status of the last command in the pipeline, i.e. code/parser (ksh, zsh), or always be 0 (most shells, including ash, bash and pdksh).
In your case, there is a simple fix that should get rid of the useless use of cat :
my $command = "cd $STEPBYSTEP_HOME/collins-parser &&" . "<models/model$model_num/events code/parser $src models/model$model_num/grammar 10000 1 1 1 1 1> $dest 2> $parse_log"; my $ret_val = `$command`; my $ret_code = $?;
If you had a useful command instead of cat , the best option would be to do without a shell at all. It also has other minor advantages: one development tool; Easier to port to non-unix systems works with names of files containing shell metacharacters (this can also be achieved by the systematic use of quotemeta ). Here is the essence of the idea (untested); perldoc -f open and perldoc perlipc can help.
use File::Slurp; if (open my $fh, "|-") { # Parent code my $ret_val = read_file($fh); close($ret_code); my $ret_code = $?; ... } else { # Child code chdir "$ENV{STEPBYSTEP_HOME}/collins-parser" or die $!; open STDIN, "<", "models/model$model_num/events" or die $!; open STDOUT, ">", $dest or die $!; open STDERR, ">", $parse_log or die $!; exec "code/parser", $src, "models/model$model_num/grammar", "1", "1", "1", "1", "1"; die $!; }