1

I have a perl script that runs a command via rsh and I need to get the exit status of that command on the remote server. The shell on both the local and remote servers is csh (I can't change this). To get the exit status on the remote server I am running:

my $output = `rsh myserver $command;echo $status`

The value of $output is the result of the command but the value of $status is never printed out.

I removed the rsh for testing and got the same results. Here is my test script:

#!/usr/local/bin/perl5.8

use strict;
use warnings;

my $output = `printf '';echo \$status`;
print "$command\n";
print "Returned: $output\n";

And here is the output:

printf '';echo $status
Returned:

If I copy and paste the command from the output into the command line the 0 prints out like I would expect:

:>printf '';echo $status
0

Any idea why this works via the command line but not via perl?

4

2 回答 2

0

The back tick operator in perl uses sh (or more precisely, the default system shell, different from the default login shell) to execute the code, not csh, and $status is not a predefined shell variable in sh.

于 2013-05-01T21:15:37.247 回答
0

Problem 1

readpipe (aka `` aka backticks) executes its command using /bin/sh, which uses $? instead of $status.

Solution 1

Adjust the command to use csh

my $status = `/bin/csh -c 'rsh myserver $command; echo $status`;
die "Can't create child: $!\n if $? < 0;
die "Child killed by signal ".($? & 0x7F)."\n" if $? & 0x7F;
die "Child exited with exit code".($? >> 8)."\n" if $? >> 8;
die "rsh exited with exit code $status\n" if $status;

Solution 2

Adjust to a bourne shell:

my $status = `rsh myserver $command; echo $?`;
die "Can't create child: $!\n if $? < 0;
die "Child killed by signal ".($? & 0x7F)."\n" if $? & 0x7F;
die "Child exited with exit code".($? >> 8)."\n" if $? >> 8;
die "rsh exited with exit code $status\n" if $status;

Solution 3

The shell actually returns the exit code of the last command it executes, so you don't need to create a new channel to grab it.

my $output = `rsh myserver $command`;
die "Can't create child: $!\n if $? < 0;
die "Child killed by signal ".($? & 0x7F)."\n" if $? & 0x7F;
die "Child exited with exit code".($? >> 8)."\n" if $? >> 8;
print($output);

It also means you are now free to capture the remote program's output without interference.


Problem 2

The contents of $command are going to be interpolated by both the local shell and the remote shell. For example, if $command contains echo *, it will list the local files instead of the remote ones. Some escaping is needed.

Solution

use String::ShellQuote qw( shell_quote );

my $local_command = shell_quote('rsh', 'myserver', $command);
my $output = `$local_command`;
die "Can't create child: $!\n if $? < 0;
die "Child killed by signal ".($? & 0x7F)."\n" if $? & 0x7F;
die "Child exited with exit code".($? >> 8)."\n" if $? >> 8;
print($output);
于 2013-05-02T00:08:26.190 回答