ssh
executes a command it's given by invoking a remote shell with a script composed of the full set of local arguments concatenated together with whitespace between them.
If you run:
# This has only syntactic quotes -- none of the quotes are literal.
ssh somehost echo "Hello World"
..then this list of arguments passed to ssh
(in C syntax, excluding the hostname and the ssh command itself) is { "echo", "Hello World", NULL }
.
Concatenated together into a string, this then becomes "echo Hello World"
.
Thus, the remote shell runs echo Hello World
, which has no syntactic quotes.
If you run:
ssh somehost echo \"Hello World\"
...then the list of commands (again, in C syntax) is { "echo", "\"Hello", "World\"", NULL }
: The quotes are literal, but the spaces were removed by the local shell (before SSH was run) during the word-splitting process.
Concatenated into a string, this becomes echo "Hello World"
. Thus, you get quotes, but lose your spaces.
By contrast, as a working (but not particularly best-practice) example, consider:
ssh somehost echo \"Hello" "World\"
Here, you're passing ssh
two arguments: The \"
s at the beginning and end are literal to the first shell (having no syntactical meaning, so the word Hello
is to that first shell unquoted); but the "
s just surrounding the whitespace is syntactical, and tells the shell to preserve that whitespace (so the spaces are quoted) when invoking ssh
. Thus, you get { "echo", "\"Hello World\"", NULL }
, which concatenates to the string echo "Hello World"
.
The best practice is to avoid this behavior by passing only a single string to ssh containing the entire script you want to run.
# This works
ssh somehost 'echo "Hello World"'
...if you want to generate that string programatically, you can do so as such (if you know that your remote shell is bash -- even bash-in-/bin/sh
mode is safe):
remote_command=( echo "Hello World" )
printf -v remote_command_q '%q ' "${remote_command[@]}"
ssh somehost "$remote_command_q"
To do that safely with any POSIX-compliant remote shell, see the Python-assisted answer in How to have simple and double quotes in a scripted ssh command