I have access to a remote server that I don't fully control and prefer to have my automated scripts that do things on that server live locally. I've found that not all commands executed inline with ssh behave the same. Example that is run in a cron job:

ssh user@remote.ip "mysqldump -u dbuser -p'pass$word' dbname > backup.sql"

The above (and many variants of it) returns mysqldump: Got error: 1045: Access denied for user 'dbuser'@'localhost' (using password: YES) when trying to connect. But i have verified the password is correct by ssh to the server and then manually running mysqldump -u dbuser -p'pass$word' dbname > backup.sql and everything works.

Another example is running something like:

ssh user@remote.ip history > history.txt 

The above output is empty but if I ssh to the other machine and then manually run history > history.txt, the output is as expected.

If I do something like the following, everything works as expected:

ssh user@remote.ip ls > ls.txt 

I understand that I can get around the mysqldump example by omitting -p'pass$word' and using a local .my.cnf file as outlined here. And a answer specifically for history can be found here.

But I would still eventually run into another command that does not working as expected even if i include them in quotes when running inline and redirecting output locally. It's as if the shell is reading stuff with different variables attached depending on how it's accessed.

How do i execute any command inline ssh as if I'm typing it manually but direct output to local machine?


The problem is your quotes:

$ word='phrase'
$ echo "pass$word"
$ echo "'pass$word'"
$ echo "'pass\$word'"

Strong quotes don't "protect" variables within weak quotes as they lose their magical properties.

One simple solution is to escape the dollarsign which may be your downfall here:

$ ssh user@remote.ip "mysqldump -u dbuser -p'pass\$word' dbname > backup.sql"

Another is to actually put the password into a variable:

$ password='pass$word' ssh user@remote.ip "mysqldump -u dbuser -p '$password' dbname > backup.sql"

A third, if you want to bring the backup to your local host anyhow is to use an SSH tunnel:

$ ssh -L 3306:localhost:3306 sleep 60 &
$ mysqldump -u dbuser -p 'pass$word' -h localhost -P 3306 dbname > backup.sql

Further, your question talks about redirecting output to your local machine, but your commands to not do this:

$ ssh user@host "echo hello > output" # creates output on remote host
$ ssh user@host "echo hello" > output # creates output on local host
| improve this answer | |
  • DopeGhoti thanks for a good answer. It cleared some of my lack of understanding. My quote in dbname > backup.sql" was in error and was originally dbname" > backup.sql...part of me trying everything and not understanding what i was doing. Is there a way to make all variables enabled or find out what's disabled when in non-interactive shell? – user310115 Sep 11 '18 at 19:08
  • In short, all variables and other parameter expansions will still take place within "weak quotes" ("), and ' ceases to be a special character within them. "Strong quotes" (') preserve as a literal string everything contained within them. – DopeGhoti Sep 11 '18 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy