How to Have Simple and Double Quotes in a Scripted Ssh Command

How to have simple and double quotes in a scripted ssh command


Using a heredoc

You can just pass your exact code on the shell's stdin:

ssh user@host bash -s <<'EOF'
sudo -i mysql -uroot -pPASSWORD --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
EOF

Note that the above doesn't perform any variable expansions -- due to the use of <<'EOF' (vs <<EOF), it passes the code to the remote system exactly, so a variable expansion ("$foo") would be expanded on the remote side, using only variables available to the remote shell.

This also consumes stdin for the heredoc containing the script to be run -- if you need stdin to be available for other purposes, that may not work as intended.



Generating an eval-safe command dynamically: Array Edition

You can also tell the shell itself to do the quoting for you. Assuming your local shell is bash or ksh:

#!/usr/bin/env bash
# ^^^^ - NOT /bin/sh

# put your command into an array, honoring quoting and expansions
cmd=(
sudo -i mysql -uroot -pPASSWORD
--execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
)

# generate a string which evaluates to that array when parsed by the shell
printf -v cmd_str '%q ' "${cmd[@]}"

# pass that string to the remote host
ssh user@host "$cmd_str"

The caveat there is that if your string expands to a value containing non-printable characters, the nonportable $'' quoting form may be used in the output of printf '%q'. To work around that in a portable manner, you actually end up using a separate interpreter such as Python:

#!/bin/sh
# This works with any POSIX-compliant shell, either locally or remotely
# ...it *does* require Python (either 2.x or 3.x) on the local end.

quote_args() { python -c '
import pipes, shlex, sys
quote = shlex.quote if hasattr(shlex, "quote") else pipes.quote
sys.stdout.write(" ".join(quote(x) for x in sys.argv[1:]) + "\n")
' "$@"; }

ssh user@host "$(quote_args sudo -i mysql -uroot -pPASSWORD sudo -i mysql -uroot -pPASSWORD)"


Generating an eval-safe command dynamically: Function Edition

You can also encapsulate your command in a function, and tell your shell to serialize that function.

remote_cmd() {
sudo -i mysql -uroot -pPASSWORD --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
}
ssh user@host bash -s <<<"$(declare -f remote_cmd); remote_cmd"

Using bash -s and passing code in a here-string or unquoted heredoc isn't needed if you know with certainty that the remote shell is bash by default -- if that were the case, you could pass the code on the command line (in place of the bash -s) instead.

If the remote command needs to be passed some variables, use declare -p to set them remotely in the same way the above uses using declare -f.

Bash Script single quotes inside of double quotes inside of single quotes

You don't need the bash -c layer; just run ssh itself directly from sudo.

sudo -H -u user1 ssh -I /home/user1/.ssh/id_rsa -f user2@machine1.domain1.com "find ./ -name \"*.txt\""

(The -I option should be unnecessary; if ssh is run as user1, then the default key is ~user1/.ssh/id_rsa. You may have meant -i anyway; -I specifies a PKCS#11 library to use, not a private key.)

That said, you cannot include single quotes inside a single-quoted string. When in doubt, use double quotes, and properly escape any nested double quotes.

Escape single quotes ssh remote command

In your first try you use double-quotes " so you need to escape the $ character:

ssh root@server "ps uax|grep bac | grep -v grep | awk '{ print \$2 }' > /tmp/back.tmp"

Also, you can use:

 ps uax | grep 'ba[c]' | ...

so then you don't need the grep -v grep step.

How to properly escape double quotes in an ssh pkill bash command?

You are better off using a heredoc for such things:

ssh root@123.123.123.123 bash -s << 'EOF'
pkill -f "stalled process name"
commands_to_restart
some_more_commands
EOF
  • bash -s ensures that you are using bash and not the user-specific shell on the remote host
  • quoting the heredoc end marker ('EOF') ensures that the content is passed as-is, without the parent shell interpreting it

Running shell command that has nested quotes via ssh

A quoted heredoc allows you to omit the outer quotes:

ssh user@host <<'END'
df | grep /dev/ | awk 'BEGIN{print "DISK", "%USAGE", "STATUS"} {split($5, a, "%"); var="GREEN"; print $1, $5, var}' | column -t
END

Escaping quotes when using SSH

Escaping the internal quote marks is the normal way. Does this not work?

sshpass -p foo ssh user@host "
cd /www/htdocs/foo/bar
echo 'Untar and remove installer'
tar -zxf install.tar.gz

sed \"s/define('ENVIRONMENT', 'development');/define('ENVIRONMENT', 'production');\" index.php > tmp && mv tmp index.php
sed \"s/define('ENVIRONMENT', 'development');/define('ENVIRONMENT', 'production');/\" admin/index.php > tmp && mv tmp admin/index.php

"

How to escape the single quote character in an ssh / remote bash command?

Use

ssh deploy@hera 'kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " '"'"'{print $2}'"'"' | head -n 1`'

Explanation:

ssh deploy@hera 'kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " '"'"'{print $2}'"'"' | head -n 1`'
> 1 <>2<> 3 <>4<> 5 <

1) First string with beginning of command: 'kill -9 `ps -ef | grep MapReduceNode | grep -v "grep" | awk -F " " '

2) Second string with only a single ' char: "'"

3) Third string with the print command: '{print $2}'

4) Fourth string with another single quote: "'"

5) Fifth string with rest of command: ' | head -n 1`'



Related Topics



Leave a reply



Submit