2

I was trying to make a small script to check if backup drive is fine and its disk usage details, and to add it to nagios as an active check in servers. Once I written one, I got some unknown errors that I don't to correct.

Script is:

#!/bin/sh

BACKUP_DRIVE='/backup'

if [[ "$( grep $BACKUP_DRIVE /etc/fstab | awk '{print $2}')" -ne "0" ]]; then 

    if [[ "$( df -h | grep $BACKUP_DRIVE | awk '{print $6}')" -ne "0" ]]; then

        if [[ "$( df -h|grep backup|awk '{print $5}' | cut -d "%" -f1)" -ge "95" ]]; then
            echo "CRITICAL: Backup Drive usage exceeded 95%"
        fi
    else
        echo "CRITICAL: Backup Drive not mounted"
    fi
else
    echo "CRITICAL: Backup Drive not added in fstab"
fi

Error is:

# sh /usr/local/src/backupcheck.sh
/usr/local/src/backupcheck.sh: line 6: [[: /backup: syntax error: operand expected (error token is "/backup")
CRITICAL: Backup Drive not added in fstab

It's getting error at the first if condition itself and not getting into the inner if conditions.

Is there any corrections need to be done at point where variable $BACKUP_DRIVE mentioned? Please help as I am a beginner to bash scripting.

3
  • why are you using /bin/sh instead of /bin/bash Commented May 30, 2014 at 19:19
  • The repeated grep | awk, df | awk, ... | awk | cut, and similar usage in here is inefficient, hard-to-read, and generally silly. Using the shell's read builtin to parse these contents a whole line at a time would be considerably simpler and more readable. Commented May 30, 2014 at 19:34
  • 1
    ...also, combining [[ ]] with -ge is silly as well -- any shell supporting [[ ]] will also support (( )), in which the far-more-readable >= can be used for numeric comparisons. Commented May 30, 2014 at 19:36

2 Answers 2

6

The immediate issue - likely the one triggering the syntax error - is:

You're using shebang #!/bin/sh, which is NOT guaranteed to be bash (and even if it is, it behaves differently), yet you're using bash-specific syntax ([[ ... ]]).

  • Use #!/bin/bash as the shebang instead.
  • When explicitly starting a script with an executable, use bash, not sh; in your example: bash /usr/local/src/backupcheck.sh

Alternatively, with the shebang as is and if you want to be able to invoke your script explicitly with sh:

  • Rewrite your script to use POSIX features only, which in the case at hand requires replacing [[ ... ]] with [ ... ] (but in the general case typically requires more changes).

You can only get away without rewriting if you know for sure that sh is actually bash on your system and you do not need the script to be portable (run on other platforms).


However, there are also issues with your conditionals:

It looks like your first 2 conditionals are meant to only test whether the enclosed command succeeds or not.

Generally, you do not need [[ ... ]] for such tests at all, and instead simply use the command directly with if, possibly negated with !, and with output suppressed as needed with >/dev/null or 2>/dev/null:

Thus, instead of your command:

if [[ "$( grep $BACKUP_DRIVE /etc/fstab | awk '{print $2}')" -ne "0" ]]; then 

you should use:

if grep $BACKUP_DRIVE /etc/fstab >/dev/null; then 

grep will indicate having found (at least) a match with exit code 0, which is (also) success from if's perspective. Thus, effectively, the if command's body will be executed if the backup drive exists.

Note that I've removed the awk command, as it (a) isn't necessary for the test and (b) actually defeats the test in that it will cause the overall result to be 0 (success), even if the grep command failed.

Similarly, your 2nd conditional should read:

if df -h | grep $BACKUP_DRIVE >/dev/null; then

Finally, your 3rd conditional is correct in principle: it captures stdout output from the pipeline and compares it to a percentage number (though double-quoting the number is not necessary and potentially confusing). However, you accidentally hard-coded the drive name, so instead it should be:

if [[ "$(df -h | grep $BACKUP_DRIVE | awk '{print $5}' | cut -d "%" -f1)" -ge 95 ]]; then

Finally:

  • You should output your error messages to stderr by redirecting the echo commands with 2>/dev/null; similarly, you should use exit 1 (or any other nonzero exit code) to exit in case of error, so as to properly signal an error condition.
  • As @Charles Duffy points out in comments on the OP, there is potential for making your commands more efficient.
Sign up to request clarification or add additional context in comments.

7 Comments

The point is valid, but [[ ]] should also work with ksh and other ksh-derived shells, like zsh.
@TrippKinetics: Yes, it works with other shells too, but (a) the question is tagged bash, and (b) the point is that the only features you're guaranteed to get when you use sh are POSIX-only features.
Then the suggestion would be to use [] rather than [[]], wouldn't it?
The question seems to imply that the script is being explicitly run using sh--# sh /usr/local/src/backupcheck.sh--so this answer is spot on.
There are two options: 1. Use bash. 2. Don't use bash. For option 1, the shebang needs to be #!/bin/bash, and the script should not be invoked as sh script-name.sh. For option 2, the script should not use [[...]]. Either option is perfectly valid.
|
1

At some point, it's trying to evaluate the $BACKUP_DRIVE parameter as a math expression. Try this instead:

grep $BACKUP_DRIVE /etc/fstab | awk '{print $2}'
if [[ $? -ne 0 ]] ; then
...

1 Comment

Not sure what you mean by evaluate the $BACKUP_DRIVE parameter as a math expression, but it is true that the stdout output from the entire expression "$( grep $BACKUP_DRIVE /etc/fstab | awk '{print $2}')" in the question will be interpreted as a number, due to use of the -ne operator. Your rewrite makes sense if the intent is to print command output first, then check whether the command succeeded. However, I suspect that only the latter is needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.