On Sat, Jan 11, 2020 at 2:02 AM Yuri <yuri@xxxxxxxxx> wrote: > > On 2020-01-11 01:38, Darren Tucker wrote: > > The command you give is always handled on the server by your shell in some > > fashion. It has to be, because SSH only specifies an opaque string for the > > remote command, so without doing so you would not be able to specify > > arguments at all. > > It's not obvious why does it have to be this way. ssh sends the command > as an array of strings. The first string is the command, and the > subsequent strings are arguments. It can easily call the same command > with the same arguments on the remote host. While it's important to understand how local shell processing works (and this is obviously out-of-scope of the ssh(1) man page), I think ssh(1) doesn't adequately explain how the "command" is executed on the remote side, and how a command is formed from multiple command tokens. >From https://github.com/openssh/openssh-portable/blob/ed3ad71b17adcd1fb4431d145f53cee1c6a1135e/ssh.c#L1069-L1072, you can see that multiple command tokens are simply joined with spaces into a single actual "command". That implies that the remote side sees all of the following variations as exactly equivalent: $ ssh host 'printargs "foo bar" baz | cat' # ssh sees a single command token locally $ ssh host printargs '"foo' 'bar"' baz \| cat # ssh sees 6 command tokens locally $ ssh host printargs '"foo bar" baz |' cat # ssh sees 3 command tokens locally >From https://github.com/openssh/openssh-portable/blob/ed3ad71b17adcd1fb4431d145f53cee1c6a1135e/session.c#L1703-L1711, you can see that these would all result approximately in running this command remotely: $SHELL -c 'printargs "foo bar" baz | cat' I say "approximately" because for simpler presentation, I used shell syntax above (as if you were to manually run the command in a remote shell), but you can see from the source that ssh actually does this via a fork-and-exec, so there would be no single quotes anywhere, for example. The output would look something like this: argv[0] = {/usr/local/bin/printargs} argv[1] = {foo bar} argv[2] = {baz} Here's a bash implementation of printargs: #!/bin/bash for (( i = 0; i <= $#; ++i )); do printf 'argv[%d] = {%s}\n' $i "${!i}" done _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev