Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I have a command like this which tells me if a system has a disk that's getting full (>=70% full):

if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi

I'd like to want to perform the above command on a remote server using using SSH. Something like:

ssh remoteserver "if [[ -n df -PTh|column -t|awk '{print $6 $7}'|awk -F"%" '{printf "%-9s %-5s\n",$1,$2}'|grep -v -e "Use" -e "Mounted"|awk '$1>70{printf "%-9s %-5s\n",$1,$2}' ]]; then echo "not present"; else echo ">70 is present"; fi"

But when I tried that, I got the following error:

HOST: remoteserver bash: -c: line 0: syntax error in conditional expression bash: -c: line 0: syntax error near /home'
bash: -c: line 0:if [[ -n 92 /home'
share|improve this question
    
This is a Super User-type question, and answers can be found in this Google search: google.com/search?q=superuser+bash+ssh+quoting –  blujay Apr 28 at 5:52
1  
@blujay What makes you think it isn't okay here? –  Seth Apr 28 at 14:52

1 Answer 1

First of all, I'd reduce that war-crime of an awk/grep/awk/grep/awk/grep/etc statement down to:

df | awk '$5~/([7-9]|10)[0-9]/'

It does everything you need to check output. You could add a {print ...} clause to the awk statement if you really needed pretty output but given that you're just checking to see if there is output, let's be reasonable about this ☺.

We can also shorten the if/else. I've also corrected the direction — yours was reversed. The whole command now looks like:

[[ -n $(df | awk '$5~/([7-9]|10)[0-9]/') ]] && echo 'ACHTUNG!' || echo 'No >=70s'

I think you'd agree that's just slightly more edifying.

Now you could probably escape this manually now and wrap it in a bash -c "..." but where's the fun in that? Instead let's save the command into a local file (say commands.txt) you can send that to the server like so:

ssh user@host $(<commands.txt)

And you could leave it there. You could actually throw a working version of your original command in there and send that over. This thing is pretty robust... But we don't want to do that... Not when we can be more clever (and cheaty) with the command and do away with the if brackets (which are the things causing the escaping problem).

We are currently running df remotely and processing it remotely. We don't need to do that. We could let ssh just run df and then handle the output locally. That instantly nixes the escaping problem but we're currently tied up in logic [[ brackets ]] which would make the rewrite a bit ugly:

[[ -n $(ssh user@host df | awk '$5~/([7-9]|10)[0-9]/') ]] && .......

Yuck.
We are better than that.
Unlike the monkeys and apes who trod before us, we have exit codes.

When something finishes running, it can return a code. These codes mean various things but generally speaking 0 means "I did exactly what I was designed to do" and anything higher means "I did bad, Bawss".

Conditional hooks like && and || look to the exit code feeding into them to decide whether or not to run. In our case this means if we tell awk to exit in a non-zero way, we can control the code flow:

ssh user@host df | awk '$5~/([7-9]|10)[0-9]/ {exit 1}' && echo 'No >=70s' || echo 'ACHTUNG!'

This also means that it will exit as soon as it detects the first >=70 value. If you had millions of drives, that could save you seconds over other leading-brand scripts. So yes, just to reaffirm what's going on in this final version:

  1. We are connecting to the server and running df remotely
  2. The output is piped back to a local instance of awk
  3. awk looks to see if the fifth column matches a regex to match 70-100
  4. If it does, it exits code 1 and the || code executes (there is a drive over 70% used)
  5. If it doesn't, it exits code 0 and the && code executes.

In previous revisions I also had a NR>1 check in the awk statements but given we're explicitly checking the value of the fifth column (and it has the be a number to work), we can safely omit that too.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.