5

I found that when I run a script locally, such as

./run.sh a "b c"

It will identify two parameters when used "$@" in run.sh. However, when used in remote machine via ssh, it won't be that.

ssh user@host ./run.sh a "b c"

So how should I achieve this ?

2
  • Does it work if you quote the whole thing, i.e. ssh user@host './run.sh a "b c"'? Commented Nov 25, 2018 at 9:13
  • 1
    @Lewis Chan: What is the error you're getting while executing in remote machine? Commented Nov 25, 2018 at 9:21

3 Answers 3

16

Understanding the problem: What's happening with your current command, ssh user@host ./run.sh a "b c", is that the local shell parses the command into "words" (applying and removing any quotes and/or escapes it sees), and gets "ssh", "user@host", "./run/sh", "a", and "b c". It takes the first (ssh) as the command, and passes the rest to it as arguments. ssh takes "user@host" as where to ssh to, and (here's the critical thing) it just sticks the rest together (separated by spaces) as the remote command to run. This gives "./run.sh a b c" as the remote command. That then gets passed to the remote shell, which (since the quotes are now gone) interprets "a", "b", and "c" as separate arguments.

In short: the quotes are getting applied and removed by the local shell, not the remote shell (which is the one you care about).

The solution: quote or escape the quotes so that the local shell treats them as just data to be passed through to the remote shell. Essentially, this means you needs two levels of quoting/escaping, so that the local shell will apply (and remove) one level, and the remote shell will apply (and remove) the second level.

Here's a simple, clean way to do it:

ssh user@host './run.sh a "b c"'

The local shell applies & removes the single-quotes, so the double-quotes get applied by the remote shell. Note that quotes generally don't nest within themselves/each other, but since double-quotes have no special meaning in a single-quoted string, it works in this case. You could also use double-quotes for both levels, but you need to escape the inner quotes:

ssh user@host "./run.sh a \"b c\""

In fact, the outer double-quotes in that aren't actually doing anything here (they make the whole thing one argument to ssh, but if they were multiple arguments they'd just get stuck back together anyway, so...). You could actually remove them:

ssh user@host ./run.sh a \"b c\"

There are actually lots of ways to do this, combining various quoting/escaping options on the local and remote shells:

ssh user@host ./run.sh a '"b c"'
ssh user@host "./run.sh a 'b c'"
ssh user@host './run.sh a b\ c'
ssh user@host ./run.sh a b\\ c

BTW, in general, echoing something is a really bad way to find out how your arguments are being parsed, because it just sticks its arguments together with spaces between. But since that's the same thing ssh does when creating the remote command, you can replace ssh user@host with echo to see what will actually be passed to the remote shell:

$ echo ./run.sh a "b c"
./run.sh a b c
$ echo './run.sh a "b c"'
./run.sh a "b c"
$ echo "./run.sh a \"b c\""
./run.sh a "b c"
$ echo "./run.sh a 'b c'"
./run.sh a 'b c'
$ echo ./run.sh a b\\ c
./run.sh a b\ c
Sign up to request clarification or add additional context in comments.

1 Comment

when trying to generate the arguments programatically the double \\[space] for [space] was the only way I could get this to work. So the following takes args in $@ and does this rargs=""; for i; do rargs="$rargs $(sed "s/ /\\\\ /g" <<< $i)"; done making a variable. then ssh user@host ./run.sh "$rargs"
0

Try this:

ssh user@host 'bash -c "./run.sh a \"b c\""'

1 Comment

While this code may answer the question, providing additional context regarding why it solves the problem would improve the answer's long-term value.
0

I was facing the similar issue as others have pointed out using the " instead of ' helped me fix the issue

ssh [email protected] "ls -a"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.