Here's everything you need to know about quoting something to protect it from shell expansion and word-splitting:
- Enclose everything other than apostrophes between apostrophes. For example,
do not becomes 'do not'.
- Use backslashes to escape apostrophes, i.e.
' becomes \'.
- Break your string up into apostrophes and other characters, apply the preceding 2 rules, then concatenate the results. For example,
don't becomes 'don'\''t'.
With these general rules, the command in your question can be properly quoted as follows:
ssh [email protected] 'awk '\''!seen[$0]++'\'' /root/.ssh/authorized_keys > /root/.ssh/authorized_keystemp'
There are more readable ways to quote the same string, but this approach is generally applicable and easy to visually verify as correct.
I find myself doing this often enough that I wrote a shell function/script to do it for me, and I use it all the time. Here it is:
#!/bin/sh -
# shellquote foo => foo
# shellquote foo&bar => 'foo&bar'
# shellquote foo'bar => 'foo'\''bar'
shellquote() {
local input="$1"
local output=""
local backslash='\'
local apostrophe="'"
if [ -z "${input}" ]; then
# Empty string => pair of apostrophes
output="''"
fi
while [ -n "${input}" ]; do
case "${input}" in
"'"*)
# Escape the apostrophe.
output="${output}${backslash}${apostrophe}"
input="${input#${apostrophe}}"
;;
*"'"*)
# Quote everything before the first apostrophe, and then escape
# the apostrophe.
output="${output}${apostrophe}${input%%${apostrophe}*}${apostrophe}${backslash}${apostrophe}"
input="${input#*${apostrophe}}"
;;
*[!+,./0-9:=@A-Z_a-z-]*)
# There are no apostrophes, but at least one character needs quoting.
# So quote the entire word.
output="${output}${apostrophe}${input}${apostrophe}"
input=""
;;
*)
# Nothing needs quoting. Output everything literally.
output="${output}${input}"
input=""
esac
done
printf '%s' "${output}"
}
main() {
local sep=''
for arg; do
printf '%s' "${sep}"
shellquote "${arg}"
sep=' '
done
}
main "$@"
10.100.10.26the remote server?