0

I'm writing this script, which should detect an error after the smart test is done. But I can't get it to detect any error, or not of course.

 if [[ smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g' != *"Completed without error"* ]; then
 echo "No error detected"
 else echo "Error detected"
 fi

Output:

./test.sh: line 19: conditional binary operator expected
./test.sh: line 19: syntax error near `--log=selftest'
./test.sh: line 19: `if [[ smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed  's/offline//g; s/00%//g' != *"Completed without error"* ]]; then'

So obviously I'm doing something wrong. But all the tutorials say two [[]] thingies, but I think the command is quite complex, it doesn't work... How can I make it work?

9
  • 1
    [[ ]] is a specific command, not part of general-purpose if syntax. If you don't want to run that command, don't put it in your syntax. Commented Jan 31, 2017 at 18:28
  • Rather, you need to capture the string output by the pipeline in order to compare it to the given pattern. Commented Jan 31, 2017 at 18:28
  • Removing the [[ ]] I get sed: can't read !=: No such file or directory sed: can't read *Completed without error*: No such file or directory Commented Jan 31, 2017 at 18:30
  • Yes, the != calls for [[ ]]. Suffice to say that this was a long and hairy enough command that it looked like a different common error at first glance. Commented Jan 31, 2017 at 18:31
  • @CharlesDuffy The typo of ] for ]] at the end didn't help that perception. Commented Jan 31, 2017 at 18:32

2 Answers 2

2

If you want to do a substring comparison, you need to pass a string on the left-hand side of the = or != operator to [[ ]].

A command substitution, $(), will replace the command it contains with its output, giving you a single string which can be compared in this way.

That is:

smartctl_output=$(smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g')
if [[ "$smartctl_output" != *"Completed without error"* ]; then
   : ...put your error handling here...
fi

or, a bit less readably:

if [[ "$(smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g')" != *"Completed without error"* ]; then
   : ...put your error handling here...
fi
Sign up to request clarification or add additional context in comments.

3 Comments

Okay, that works, kind off.. I'm not sure with what the if error compares though... It says error detected although there are none. Is there something wrong with the != *"Completed without error"* comparison? [root@operations ~]# ./test.sh Error detected [root@operations ~]# smartctl --log=selftest /dev/sda | awk 'NR>7 {print $4,$5,$6,$7}' | sed 's/offline//g; s/00%//g' Completed without error Completed without error
declare -p smartctl_output to print the variable's contents unambiguously.
Okay, got it. I actually didn't think of making it a variable, I was thinking too complex! Thank you for giving me another look on it!
2

You are confusing things. If the command you want to test is smartctl, don't replace it with [[. You want either or, not both. (See also e.g. Bash if statement syntax error)

Anyway, piping awk through sed and then using the shell to compare the result to another string seems like an extremely roundabout way of doing things. The way to communicate with if is to return a non-zero exit code for error.

if smartctl --log=selftest /dev/sda |
   awk 'NR>7 { if ($4 OFS $5 OFS $6 OFS $7 ~ /Completed without error/) e=1; exit }
       END { exit 1-e }'
then
     echo "No error detected"
else
     echo "Error detected"
fi

6 Comments

Your command will always exit 1, though you have exit 0 before END block, for example run this echo 1 | awk '{exit 0}END{exit 1}'; echo $?
You can do something like this to correct, awk 'BEGIN{e=1}NR>7 { if ($4 OFS $5 OFS $6 OFS $7 ~ /Completed without error/) e=0} END { exit e&&1 }'
That works! Got one question, if the output gives for example error on Disk /dev/sda, will it still says no error detected because it reads the word "error"? Or does it only compare to the complete /Completed without error/ string?
@Florius, /Completed without error/ will only match that exact string (absent the delimiters) in full.
@AkshayHegde Thanks for the comments, fixed the exit code handling.
|

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.