From a bash terminal, I want to log-in to a computing node and execute some command, for example, I do this to check the running jobs
ssh -t node1 'top -bn1 | grep R | grep -v top'
This logins to node1
and runs the top
command and grep desired output.
Now I want to check the memory load of the node. I have taken this code from here https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load
free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
Now, I can not just do
ssh -t node1 '<above command>'
as there are multiple quote that will affect the command. Is there a way to execute the above command?
CodePudding user response:
For instance with
ssh -t node1 'free -m | '"awk 'NR==2"'{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
The idea here is to put the string together in pieces. When you have a sequence containing a single quote, wrap it into double quotes. The parts containing a variable expansion or a double quote gets wrapped between single quotes.
CodePudding user response:
You can use here-doc to avoid quoting issues :
ssh node1 << 'EOF'
free -m | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
EOF
Notice quotes around EOF so as to pass content as is.
We don't usually use -t
of ssh if we just run commands directly
CodePudding user response:
Your command contains single quotes, so you cannot pass this command to ssh
as a single-quoted string (single quotes cannot be escaped within single quotes).
Therefore, your options are as follows:
- Either remove the single quotes from the command and change it so that it uses only double quotes.
- ...or pass the command to
ssh
in double quotes (ssh -t node1 "<above command>"
). You will then need to escape special characters in<above command>
(like$
or other double quotes) to prevent local expansion.
In your particular case, you can also work around this issue by not running awk
on the remote side, but running it locally instead. So this will work:
ssh -t node1 'free -m' | awk 'NR==2{printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3,$2,$3*100/$2 }'
In many cases this leads to a simpler and more readable solution. (However, you need to be aware that if you process remote data locally, then all remote data is transferred through ssh first -- so don't do this when you need to grep tons of data).
CodePudding user response:
Is there a way to execute the above command?
First define a function with the commands you want to execute. Write normal well-formatted readable code, just in a function. Remember to use shellcheck to check for common mistakes.
f() {
free -m |
awk '
NR==2 {
printf "Memory Usage: %s/%sMB (%.2f%%)\n", $3, $2, $3 * 100 / $2
}
'
}
Then you will need a simple small function escaping function, that I also posted here:
sshqfunc() { echo "bash -c $(printf "%q" "$(declare -f "$1"); $1 \"\$@\"")"; };
Then just:
ssh -t node1 "$(sshqfunc f)"