198

I'm new to bash and I'm stuck at trying to negate the following command:

wget -q --tries=10 --timeout=20 --spider http://google.com
if [[ $? -eq 0 ]]; then
        echo "Sorry you are Offline"
        exit 1

This if condition returns true if I'm connected to the internet. I want it to happen the other way around but putting ! anywhere doesn't seem to work.

Benjamin W.
  • 33,075
  • 16
  • 78
  • 86
Sudh33ra
  • 2,237
  • 3
  • 11
  • 16

5 Answers5

280

You can choose:

if [[ $? -ne 0 ]]; then       # -ne: not equal

if ! [[ $? -eq 0 ]]; then     # -eq: equal

if [[ ! $? -eq 0 ]]; then

! inverts the return of the following expression, respectively.

Cyrus
  • 69,405
  • 13
  • 65
  • 117
  • 14
    are the double brackets necessary? why is that? – Alexander Mills Dec 05 '16 at 07:25
  • 1
    @AlexanderMills: There are several ways to do this. With double or single brackets or with `test` command: `if test $? -ne 0; then` – Cyrus Dec 05 '16 at 18:05
  • 8
    This answer is unnecessary verbose. `if` expects a statement that is either 0 or 1, so you can use the command itself and invert it: `if ! wget ...; then ...; fi` – Nils Magnus May 04 '19 at 22:32
100

Better

if ! wget -q --spider --tries=10 --timeout=20 google.com
then
  echo 'Sorry you are Offline'
  exit 1
fi
Steven Penny
  • 82,115
  • 47
  • 308
  • 348
  • 1
    Important: keep a space between the `!` and the following command otherwise you will be doing a history expansion. https://unix.stackexchange.com/questions/3747/understanding-the-exclamation-mark-in-bash – Roland Apr 10 '20 at 11:56
  • 2
    Steven why do you have only 1 reputation? – Roland Apr 10 '20 at 11:58
9

If you're feeling lazy, here's a terse method of handling conditions using || (or) and && (and) after the operation:

wget -q --tries=10 --timeout=20 --spider http://google.com || \
{ echo "Sorry you are Offline" && exit 1; }
Cole Tierney
  • 7,737
  • 1
  • 23
  • 29
  • 10
    In real-life scripts you should change the `&&` after the echo command to a `;`. The reason for this is that if the output is being redirected to a file on a full disk, the `echo` will return failure and the `exit` will never fire. This is probably not the behaviour you want. – Score_Under Jan 17 '16 at 21:06
  • or you can use `set -e` and failing `echo` will exit the script anyway – Jakub Bochenski Sep 13 '17 at 13:21
4

You can use unequal comparison -ne instead of -eq:

wget -q --tries=10 --timeout=20 --spider http://google.com
if [[ $? -ne 0 ]]; then
    echo "Sorry you are Offline"
    exit 1
fi
Victor Schröder
  • 5,262
  • 1
  • 34
  • 43
davidhigh
  • 12,239
  • 1
  • 34
  • 64
4

Since you're comparing numbers, you can use an arithmetic expression, which allows for simpler handling of parameters and comparison:

wget -q --tries=10 --timeout=20 --spider http://google.com
if (( $? != 0 )); then
    echo "Sorry you are Offline"
    exit 1
fi

Notice how instead of -ne, you can just use !=. In an arithmetic context, we don't even have to prepend $ to parameters, i.e.,

var_a=1
var_b=2
(( var_a < var_b )) && echo "a is smaller"

works perfectly fine. This doesn't appply to the $? special parameter, though.

Further, since (( ... )) evaluates non-zero values to true, i.e., has a return status of 0 for non-zero values and a return status of 1 otherwise, we could shorten to

if (( $? )); then

but this might confuse more people than the keystrokes saved are worth.

The (( ... )) construct is available in Bash, but not required by the POSIX shell specification (mentioned as possible extension, though).

This all being said, it's better to avoid $? altogether in my opinion, as in Cole's answer and Steven's answer.

Benjamin W.
  • 33,075
  • 16
  • 78
  • 86