I\'m building a small set of scripts for remotely starting, stopping and checking the status of a process. The stop
of these scripts should look for a process a
This is not ssh
or awk
handling the quotes, it is the shell (and they are necessary to keep the shell from handling other characters specially, like $
). Nesting them is not supported (although other structures, such as $()
may nest even while containing quotes), so you'll need to escape the single quotes separately. Here are a couple of methods:
$ echo 'Don'"'"'t mess with this apostrophe!'
Don't mess with this apostrophe!
$ echo 'Don'\''t mess with this apostrophe!'
Don't mess with this apostrophe!
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`'
You can't include a single quote in a single-quoted string. However, that doesn't matter because a single argument can have more than one quoted segment (as long as there is no unquoted whitespace or other self-delimiting characters.)
For example:
ssh deploy@hera 'kill -9 `ps -ef |
grep MapReduceNode |
grep -v "grep" |
awk -F " " '\''{print $2}'\'" |
head -n 1`"
However, that command line is very clunky. If possible, you should use the pkill utility, which would reduce all that to ssh deploy@hera 'pkill -SIGKILL MapReduceNode'
.
Otherwise you could do all the string manipulation in a single awk
invocation (untested, but I think it will work):
ssh deploy@hera 'ps -ef |
awk "/[M]apReduceNode/{system(\"kill -9 \"$2)}"'
(unlike the original, this will kill all MapReduceNode tasks rather than some arbitrary first one. If you really want to just do in one task, add ; exit
to the awk action.)
Another example is to deal with simple or double quotes because for me for example I needed interpretation and variable replacements. If I want to make a function to display a msg to the macOS of my woman I can do followings:
ssh womanLptp "osascript -e 'tell app \"System Events\" to display dialog \"${1}\"'"
There are two more options I don't see mentioned in any of the other answers. I've left the grep/grep/awk/head pipeline intact for demonstration purposes, even though (as alluded to in rici's answer) it could be reduced to something like
awk -F ' ' '/MapReduceNod[e]/ {print $2; exit}'
Using double quotes for the whole ssh command:
ssh deploy@hera "kill -9 \$(ps -ef |
grep MapReduceNode | grep -v \"grep\" | awk -F ' ' '{print \$2}' | head -n 1)"
Notice that I can use single quotes in the command now, but I have to escape other things I don't want expanded yet: \$()
(which I've used instead of backticks), double quotes \"
, and print \$2
.
A here-doc with quoted delimiter:
ssh -T deploy@hera <<'EOF'
kill -9 $(ps -ef | grep MapReduceNode | grep -v 'grep' |
awk -F ' ' '{print $2}' | head -n 1)
EOF
The -T
prevents ssh from complaining about not allocating a pseudo-terminal.
The here-doc with quoted delimiter is extra nice because its contents don't have to be modified at all with respect to escaping things, and it can contain single quotes.