1

I got this command that works perfectly on the remote server

perl -ne 'print "$1,$2,$3\n" if /^[^\[]*\[\K([^]]+)[^{]*{[^[]*\["\K([^"]+)(?:(?!SmsJob).)*SmsJob:\K([0-9a-f]+)/' /path/to/file.log

but then when I try to run it locally by saving it as a shell function like so:

function getRemoteLogs()
{
    ssh -i $ssh_key_file ubuntu@$1 -t 'perl -ne `print "$1,$2,$3\n" if /^[^\[]*\[\K([^]]+)[^{]*{[^[]*\["\K([^"]+)(?:(?!SmsJob).)*SmsJob:\K([0-9a-f]+)/` /path/to/file.log' > local.txt
}

where $1 is the ip of the remote server

it returns this error:

bash: command substitution: line 0: syntax error near unexpected token `('
bash: command substitution: line 0: `print "$1,$2,$3\n" if /^[^\[]*\[\K([^]]+)[^{]*{[^[]*\["\K([^"]+)(?:(?!SmsJob).)*SmsJob:\K([0-9a-f]+)/'
Unknown regexp modifier "/w" at -e line 1, at end of line
Unknown regexp modifier "/w" at -e line 1, at end of line
Unknown regexp modifier "/w" at -e line 1, at end of line
syntax error at -e line 1, near "18.log
"
Execution of -e aborted due to compilation errors.

how do I do this?

4
  • 1
    ` has a totally different meaning to '.
    – choroba
    Commented Mar 15, 2019 at 13:46
  • great! and so now do I use ' properly instead of `?
    – abbood
    Commented Mar 15, 2019 at 13:52
  • this isn't working ssh -i $ssh_key_file ubuntu@$1 -t 'perl -ne \'print "$1,$2,$3\n" if /^[^\[]*\[\K([^]]+)[^{]*{[^[]*\["\K([^"]+)(?:(?!SmsJob).)*SmsJob:\K([0-9a-f]+)/\' /var/www/toters/storage/logs/info-2019-02-18.log' > local.txt
    – abbood
    Commented Mar 15, 2019 at 13:55
  • 2
    You can't escape ' inside a '. You need to end the outer quotes, escape the quote, and start the quotes again.
    – choroba
    Commented Mar 15, 2019 at 13:56

2 Answers 2

1

The backticks you are using tell Perl to pass everything inside them to the underlying shell as a command - like exec or system() would do. Here's a link that discusses backticks in Perl.

You do need to quote the whole perl command for the remote server, but you will have to use double quotes. Then you must escape the inner double quotes and the variables that would otherwise expand.

Try this out:

ssh -i $ssh_key_file ubuntu@<remote ip> "perl -ne 'print \"\$1,\$2,\$3\n\" if /^[^\[]*\[\K([^]]+)[^{]*\{[^[]*\[\"\K([^\"]+)(?!SmsJob).)*SmsJob:\K([0-9a-f]+)/' /path/to/file.log" > local.txt

I also escaped the left brace after the glob, because perl complained about it.

Also, I don't think you need to force a pseudo tty on the connection, so you can probably drop -t. If that gives you trouble then I would try it with -T first to disable pseudo TTY creation.

7
  • 1
    You do need to quote the whole command, as SSH does not preserve individual arguments – it just concatenates them and the result is used as a single argument for /bin/sh -c "..." (similarly to how 'eval' works). The remote side wouldn't know that the part after -ne had been single-quoted locally. Commented Mar 15, 2019 at 14:19
  • Okay, thank you for that correction. But he could use double quotes, right? That way he could have the single quotes preserved in the command. I am finally at a computer now, so I will do some testing on this. Commented Mar 15, 2019 at 14:24
  • 1
    Yes, but the inner double quotes and the Perl $variables would need to be backslash-escaped in addition to that. Commented Mar 15, 2019 at 14:26
  • Sure, that is what I was about to check. After I do this actual testing I'll edit my answer above. Thanks for the help ;) Commented Mar 15, 2019 at 14:27
  • 1
    Trick for bash 5.0 and later: cmd=(perl -ne 'print "$1,$2,$3\n" if /someregex/' /path/to/file.log); ssh $host "${cmd[*]@Q}" Commented Mar 15, 2019 at 14:39
0

Here are a couple of alternatives to Guy's answer.

I shortened your original command to make it (slightly) more readable:

perl -ne 'print "$1,$2,$3\n" if /^([^\[]*)(?:.*(?!SmsJob).)*/' /var/log/syslog

Now with ssh, if you put the perl code in double-quotes, you could use qq{} inside, instead of escaped double-quotes. However, you would still need to escape the $ variables:

ssh -i $id $user@$host 'perl -ne "print qq{\$1,\$2,\$3\n} if /^([^\[]*)(?:.*(?!SmsJob).)*/" /var/log/syslog'

A more readable alternative is to use the suggestion in @choroba's comment: close and reopen the quotes:

ssh -i $id $user@$host 'perl -ne ' "'" 'print "$1,$2,$3\n" if /^([^\[]*)(?:.*(?!SmsJob).)*/' "'" /var/log/syslog

or slightly shorter by keeping the first part in double-quotes:

ssh -i $id $user@$host "perl -ne '" 'print "$1,$2,$3\n" if /^([^\[]*)(?:.*(?!SmsJob).)*/' "'" /var/log/syslog

(tested with a local Ubuntu 16.04, and a remote Debian 9)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .