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
Why Is Rcx Not Used for Passing Parameters to System Calls, Being Replaced with R10
Number of Executed Instructions Different for Hello World Program Nasm Assembly and C
What Does "-Sh: Executable_Path:Not Found" Mean
Bash Script - Iterating Over Output of Find
Running Shell Script in Parallel
Negate If Condition in Bash Script
Signing Windows Application on Linux-Based Distros
Unix Standard Directory to Put Custom Executables or Scripts
Difference Between Arm-Eabi Arm-Gnueabi and Gnueabi-Hf Compilers
Installing Git with Non-Root User Account
How to Configure Linux Capabilities Per User
How to Install PHP 7 on Ec2 T2.Micro Instance Running Amazon Linux Distro
Linux Command to Check If a Shell Script Is Running or Not
How to Get the Difference (Only Additions) Between Two Files in Linux
Explaining the 'Find -Mtime' Command