Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

hello all, I have a lil issue with my regexp: When I run this line as it in a script I dont have any problem .
$line=`perl \-e '\$s = shift; \$SIG{ALRM} = sub { kill INT => \$p }; e +xec(\@ARGV) unless \$p = fork; alarm \$s; waitpid \$p, 0 ' 3 'ls -ltr +'`;
but when I run the same cmd with ssh I get an error.
$cmd=`ssh server 'perl \-e '\$s = shift; \$SIG{ALRM} = sub { kill INT +=> \$p }; exec(\@ARGV) unless \$p = fork; alarm \$s; waitpid \$p, 0 ' + 3 'ls -ltra' '`;
Can anyone suggest where I am going worng in that please Thank you kindly

Replies are listed 'Best First'.
Re: perl -e in ssh
by ikegami (Patriarch) on Apr 13, 2010 at 16:46 UTC
    Look where your single quotes start and end in the second command. Completely different from the first command.
Re: perl -e in ssh
by salva (Canon) on Apr 13, 2010 at 17:36 UTC
    That's because you have an additional shell in the remote side interpreting escapes and quoting.

    You need to add an extra level of quoting resulting in...

    'perl\\ -e\\ \\\'\\$s\\ \\=\\ shift\\;\\ \\$SIG\\{ALRM\\}\\ \\=\\ sub\ +\ \\{\\ kill\\ INT\\ \\=\\>\\ \\$p\\ \\}\\;\\ exec\\(\\@ARGV\\)\\ unl +ess\\ \\$p\\ \\=\\ fork\\;\\ alarm\\ \\$s\\;\\ waitpid\\ \\+\\$p\\,\\ + 0\\ \\\'\\ 3\\ \\\'ls\\ -ltr\\\''
    Or you can use Net::OpenSSH and forget about this quoting nightmare:
    use Net::OpenSSH; my $ssh=Net::OpenSSH->new($server); my $line = $ssh->capture(perl => -e => <<'EOC', 3, 'ls -ltr'); $s = shift; $SIG{ALRM} = sub {kill INT => $p}; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0; EOC
    And check also GRID::Machine, that allows to run perl code in remote machines through SSH.
      Or automate the quoting:
      sub shell_quote { my $s = @_ ? $_[0] : $_; return $s if $s =~ /^[a-zA-Z0-9-_]+\z/; $s =~ s/'/'\\''/g; return "'$s'"; } my $server = 'localhost'; my $cmd = 'ls -ltra'; my $timeout = 3; my $watchdog = <<'__EOI__'; $t = shift; $SIG{ALRM} = sub { kill INT => $p }; exec(@ARGV) unless $p = fork; alarm $t; waitpid $p, 0 #exit(...) __EOI__ my $watchdog_cmd = join ' ', map shell_quote, perl => "-e$watchdog", $timeout, $cmd; my $ssh_cmd = join ' ', map shell_quote, ssh => $server, $watchdog_cmd; my $output = `$ssh_cmd`;

      But wouldn't it make more sense to include ssh in the timeout?

      ... my $ssh_cmd = join ' ', map shell_quote, ssh => $server, $cmd; my $watchdog_cmd = join ' ', map shell_quote, perl => "-e$watchdog", $timeout, $ssh_cmd; my $output = `$watchdog_cmd`;

      Tested.

        the above code just prints out ls -ltra instead of the output of the cmd
        ikegami the code just blurts out ksh: 4: not found Please guys can point out where I am going wrong.
        ikegami the code just blurts out ksh: 4: not found also there is something about this line thats not right $s = s/'/'\\''/g ; Please guys can point out where I am going wrong.
      I dont have OpenSSH module. But I am still getting this error sh: syntax error at line 1: `(' unexpected where else can I correct
Re: perl -e in ssh
by graff (Chancellor) on Apr 14, 2010 at 01:37 UTC
    Given that you have ssh access to the particular server in question, I would expect that you have a home directory there with write permission, where you can store a perl script as an actual file. So why not just put your perl one-liner into a file on the remote server, and make things simple and clear in the local script:
    $cmd = `ssh server perl my-remote-one-liner`;
    I couldn't tell from the OP what sort of args the remote one-liner script was expecting for @ARGV. If including those within the back-ticks for the ssh command is complicated, I would switch from using back-ticks to opening a pipeline file handle, so that I could submit the args as separate list elements (not to be interpreted by the remote shell):
    { my @ssh_cmd = qw/ssh server perl my-remote-one-liner arg1 arg2/; open( my $ssh, "-|", @ssh_cmd ) or die "ssh failed: $!"; local $/; $cmd = <$ssh>; }
    Note that the curlies establish scope for the "local" use of slurp mode, and for the shell file handle (using "my" within the block limits the scope for the variable, whether or not you "use strict;" -- but you do use strict, right?
Re: perl -e in ssh
by moritz (Cardinal) on Apr 13, 2010 at 16:42 UTC
    What's the error message?
      I am running this cmd
      $line=`ssh server 'perl \-e '\$s = shift; $SIG{ALRM} = sub { kill INT +=> \$p }; exec(@ARGV) unless \$p = fork; alarm \$s; waitpid \$p, 0 ' +3 'ls -ltra' ' `;
      and I am getting this error
      syntax error at -e line 1, near "=" Execution of -e aborted due to compilation errors. sh: =: not found
        That's a quoting issue: you have '...' around the entire perl command which you pass to ssh, and also '...' around the -e one liner - that's not going to work. Oh, and this has nothing to do with perl, but everything with the shell.

        You could try another quoting character, like ", and escape things where necessary.