2
$ ssh root@123.123.123.123
123.123.123.123# pkill -f "stalled process name"; commands_to_restart; some_more_commands;
many many lines of output demonstrating success
123.123.123.123# exit;

ALL WORKS PERFECTLY

$ ssh root@123.123.123.123 "pkill -f "\""stalled process name"\"";"\
> "commands_to_restart; some_more_commands;";

no output, DOES NOTHING.

$ ssh root@123.123.123.123 "echo "\""pkill -f "\"\\\"\""stalled process name"\"\\\"\""; "\
> "commands_to_restart; some_more_commands;"\"";";
pkill -f "stalled process name"; commands_to_restart; some_more_commands;

so... TWO stages of quote escaping works as expected...

How do I get a single layer of quote escaping to work with ssh/bash? Since quoting works perfectly in two layers I have a feeling it has less to do with the quoting and more to do with some aspect of sshs handling of the terminal. Yet, as far as I know the commands do nothing but simple and regular IO to standard output and no input.

codeforester
  • 39,467
  • 16
  • 112
  • 140
user3338098
  • 907
  • 1
  • 17
  • 38
  • 2
    Nothing to do with terminal handling, per se. The thing to understand is that ssh concatenates all its arguments together into a single string, and sends that string over the wire. – Charles Duffy May 09 '18 at 01:47
  • 2
    Consequently, syntactic quoting that went into the boundaries between those arguments is entirely discarded -- it was consumed by your local shell in forming ssh's argument list, but ssh then throws that information away: Locally-syntactic quotes are discarded by the local shell, and *literal* quotes passed through within the argument list are treated as syntax by the remote shell. – Charles Duffy May 09 '18 at 01:53
  • 1
    This is a design misfeature, but it's a design misfeature that can only be fixed with a new wire protocol (that passes multiple strings rather than just one over the wire), so the chances of it being fixed in the future are... vanishingly unlikely. – Charles Duffy May 09 '18 at 01:54
  • @CharlesDuffy It turns out the quoting *IS* perfect! Spent hours reading up on everything about the shell/ssh quote escaping process before realizing the issue was that the pkill was _self-referential_ to the `sh -c '... pkill -f "other process";...'`process started by ssh. lol – user3338098 May 12 '18 at 00:09
  • the solution is to do `ssh "pkill \"\\`echo O\\`ther process\"; other_commands;"` – user3338098 May 12 '18 at 00:27
  • 1
    The fact that you *need to quote differently than you would for a local command* is imperfect, and is what I was saying above would be unnecessary if SSH weren't misdesigned. – Charles Duffy May 12 '18 at 16:45

2 Answers2

6

You are better off using a heredoc for such things:

ssh root@123.123.123.123 bash -s << 'EOF'
    pkill -f "stalled process name"
    commands_to_restart
    some_more_commands
EOF
  • bash -s ensures that you are using bash and not the user-specific shell on the remote host
  • quoting the heredoc end marker ('EOF') ensures that the content is passed as-is, without the parent shell interpreting it
codeforester
  • 39,467
  • 16
  • 112
  • 140
  • 2
    accepted becuase this doesn't cause `bash -c pkill\040-f\040"stalled\040process\040name";commands_to_restart;some_more_commands;` to show up on the command line arguments on the server and cause pkill to kill its own shell environment, which was the actual problem I was having. – user3338098 Jul 27 '18 at 18:20
1

Try:

ssh root@123.123.123.123 'pkill -f "stalled process name"; commands_to_restart; some_more_commands'

With the command in single-quotes, there is no need to escape the inner double-quotes.

If you prefer to use only double-quotes, then a single-escape of the inner double-quotes should be satisfactory:

ssh root@123.123.123.123 "pkill -f \"stalled process name\"; commands_to_restart; some_more_commands"
John1024
  • 109,961
  • 14
  • 137
  • 171
  • not accepted because quoting was not the issue. This will cause ssh to run `bash -c pkill\040-f\040"stalled\040process\040name";commands_to_restart;some_more_commands;` and thus pkill will kill its own shell environment and prevent execution of `commands_to_restart`. – user3338098 Jul 27 '18 at 18:24