Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First echo missing when using bash -c over SSH

Tags:

bash

ssh

quotes

While debugging a script that runs various commands remotely, I noticed some problems getting output from echo.

I realize that the bash -c isn't necessary here, but it still has me wondering.

In my shell:

> bash -c "echo hello && echo hi"
hello
hi

But, if I bring SSH into the picture:

> ssh ${myhost} bash -c "echo hello && echo hi"

hi

Yet, date outputs, even though that first echo didn't:

> ssh ${myhost} bash -c "date && echo hi"
Thu Jun  3 21:15:26 UTC 2021
hi

What's going on here?

like image 397
squidpickles Avatar asked Jul 22 '26 11:07

squidpickles


2 Answers

When you run a command via ssh like this, it's parsed twice: first on the local computer (before it's passed to the ssh command as arguments), then again on the remote computer before it's actually executed. Each time it's parsed, the shell will apply and remove quotes and escapes. That means the double-quotes you have around the command get applied and removed by the local shell, before the command is sent to the remote shell. So what looks like this command:

bash -c "echo hello && echo hi"

Turns into this by the time the remote shell sees it:

bash -c echo hello && echo hi

...which is two separate commands, bash -c echo hello and echo hi. The second one, echo hi, works as you expect, but the first may not.

With bash -c, the argument immediately after that is taken as the command string to execute, and any further arguments are assigned to $0, $1, etc as it runs. So bash -c echo hello just runs echo with $0 set to "hello". So it prints a blank line.

If you want the command to be executed as you expect, you need two layers of quotes and/or escapes, one to be applied and removed by the local shell and another to be applied and removed by the remote shell. Any of these will work:

# Single-quotes for local shell, double for remote
ssh ${myhost} 'bash -c "echo hello && echo hi"'

# Double-quotes for local shell, single for remote
ssh ${myhost} "bash -c 'echo hello && echo hi'"

 # Double-quotes for local shell, escaped doubles for remote
ssh ${myhost} "bash -c \"echo hello && echo hi\""

# Single-quotes for local shell, escaped characters for remote
ssh ${myhost} 'bash -c echo\ hello\ \&\&\ echo\ hi'

...and many more possibilities. Note that if the command string contains anything like variable references or command substitutions, you need to pay attention to whether you want them to expand on the local or remote computer, and make sure the quoting/escaping method you use accomplishes that.

BTW, in this case since you're running a command with bash -c, there's actually a third layer of parsing done by the shell invoked by bash -c. If that command has anything that needed quoting/escaping, keeping the levels straight will be even more complex.

like image 145
Gordon Davisson Avatar answered Jul 25 '26 02:07

Gordon Davisson


The command that arrives to the server is : bash -c echo hello && echo hi

ie without quote

and if you run this cde locally, it produces the same output

If you want the good result

ssh mm 'bash -c "echo hello && echo hi"'

like image 22
Dri372 Avatar answered Jul 25 '26 04:07

Dri372



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!