I'd like to grep the output of ifconfig in bash

6.1k views Asked by At

I'm making a small script to determine if I have an internet connection on OSX. More of just practice, I suppose.

In terminal "ifconfig | grep -cs 'status: active' " will return 1 if there's at least one active connection

The script I have is this

    #!/bin/bash

detect(){
ONLINE=ifconfig | grep -cs 'status: active'
}

if [[ detect = 1 ]]
then
        echo "Online"
else
        echo "Offline"
fi

However the Variable ONLINE always returns 0. From what I can tell/understand, this has to do with using a pipe inside of the script. A sub-pipe is used when running the command, and ONLINE just gets stuck with 0 as the sub-pipe closes.

I think I see the issue, but I don't know how to get around this. I saw a bunch of work arounds for scripts having this issue with while loops, but nothing where I need the output from ifconfig fed into grep.

4

There are 4 answers

1
Soosh On

use this:

ONLINE=$(ifconfig | grep -cs 'status: active')


cause without "$" what bash will return is the result of the command being successful or not and if it is successful it is always zero.

4
Red Cricket On

Or you can just keep it simple like this ...

ifconfig | grep 'status: active' > /dev/null 2>&1
if [ $? == 0 ]
then
   echo "online"
else
   echo "offline"
fi
0
Samveen On

As none of the answers explain the exact issue with your script, I'm adding an answer.

The issue lies with the line ONLINE=ifconfig | grep -cs 'status: active'.

What is wrong is that there is no command substitution ($(...) or `...`) used in the line. As correctly suggested by other answers as well, the assignment needs to be $(ONLINE=ifconfig | grep -cs 'status: active').

What this line actually does is that it assigns the string "ifconfig" to the variable ONLINE and pipes the output of that (no output in this case) through grep -cs ...

One point to note is that this assignment is only for the duration of that line, and does not survive till the next line. To illustrate:

samveen@precise:~$ I=0
samveen@precise:~$ echo $I
0
samveen@precise:~$ I=1 | echo "blank"
blank
samveen@precise:~$ echo $I
0

Edit: I totally missed another very important point: Subroutines do not return values in bash, just exit status

Thus capturing variables from subroutine calls needs the subroutine to echo it's expected return value and it's call needs an assignment with command substitution.

Something like this:

detect(){
    ONLINE=$(ifconfig | grep -cs 'status: active')
    echo $ONLINE
}

if [[ $(detect) -eq 1 ]]
then
    echo "Online"
else
    echo "Offline"
fi

Also, use -eq to test numeric equality.

Finally, the shortest way to do what you want is

ifconfig | grep -q 'status:active' && echo "online" || echo "offline"
3
Floris On

Several problems with your current script:

  1. You set a variable ONLINE, but you test for detect.
  2. You don't actually assign the result of the ifconfig | grep -cs 'status: active' command to the variable ONLINE
  3. You use = instead of == to test for equality

The following would seem to be closer to what you intended:

#!/bin/bash
ONLINE=$(ifconfig | grep -cs 'status: active')
if [[ $ONLINE == 1 ]]
then
  echo "online"
else
  echo "offline"
fi