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 [email protected] "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 [email protected] 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 [email protected] 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?


1 Answer 1


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 [email protected] "mysqldump -u dbuser -p'pass\$word' dbname > backup.sql"

Another is to actually put the password into a variable:

$ password='pass$word' ssh [email protected] "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
  • 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
    Commented Sep 11, 2018 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
    Commented Sep 11, 2018 at 19:48

You must log in to answer this question.