I think it's a duplicate of the following question: ssh command with quotes. It had been noted, but the author here stated:
after reading that I'm still not sure why it works like this
therefore this answer tries to explain the issue specifically in the context of the code used in the current question.
The most important information from this good answer to the linked question is:
SSH executes the remote command in a shell. It passes a string to the remote shell, not a list of arguments. The arguments that you pass to the ssh
commands are concatenated with spaces in between.
If you locally run
ssh devops_staging@127.0.0.1 /home/devops_staging/deployJob.sh example
then the arguments ssh
recognizes as code to be passed to the remote side Will be: /home/devops_staging/deployJob.sh
, example
. The string from concatenation of the arguments will be
/home/devops_staging/deployJob.sh example
and this will be the shell code to run on the remote side. It so happens it's the string you want.
But if you locally run
ssh devops_staging@127.0.0.1 bash -c "/home/devops_staging/deployJob.sh example"
then the arguments will be: bash
, -c
, /home/devops_staging/deployJob.sh example
and the string for the remote shell will be
bash -c /home/devops_staging/deployJob.sh example
(as if the arguments were: bash
, -c
, /home/devops_staging/deployJob.sh
, example
) and this is not the shell code you want to run on the remote side. Here example
will not belong to the option-argument to -c
(it will be like the second sh
in this another question).
If you want exactly this string as remote code:
bash -c "/home/devops_staging/deployJob.sh example"
then the easiest method is to pass the string to a local ssh
as a single argument:
ssh devops_staging@127.0.0.1 'bash -c "/home/devops_staging/deployJob.sh example"'
The single-quoted argument contains all the shell code you want to pass to a shell started by the SSH server on the remote side.
Note you could even do this locally:
ssh devops_staging@127.0.0.1 'bash -c "/home/devops_staging/deployJob.sh' 'example"'
where double-quotes (for the remote shell) belong to two separate local arguments, the resulting string for a remote shell will be the same.
Note how many tools interpret and digest the command until the code in your (remote) deployJob.sh
runs:
The local shell does word splitting, quote removal (and in general few other things). In the result ssh
may get one or more arguments it interprets as code to be passed to the remote side.
ssh
concatenates these arguments with spaces in between, so a single string is passed to a remote shell.
The remote shell performs word splitting, quote removal (and in general few other things) on its own. It runs some command(s).
If the command is bash -c …
then yet another (remote) shell will parse the code being the option argument to -c
. Word splitting, quote removal and other things will be performed by this shell as well.
And if deployJob.sh
contains a sane shebang (or none) then there will be yet another (remote) shell that will in turn interpret the file.
In general you need to predict and mastermind what tool gets what arguments after all the previous tools digested their arguments; and what arguments it will pass to the next tool. You need to design your local command, so the ultimate tool gets exactly what you want it to get.