1

I'm currently trying make a tool in bash that will just check for alive systems. I don't need it to be some crazy complicated tool. I just need it to tell me my machines are up and running. I know my script is garbo... That's why I'm here.

#!/bin/bash

here()
{
ping -c 1 $1 > dev/null
echo "Good morning, Here are the machines that are up and running: $i"
}

for i in insert ip range
do here $i
done
2
  • Double-quote your variables when you use them Nov 18, 2020 at 22:20
  • 2
    Why is nmap not acceptable? It implements the ping scan it seems like you're trying to achieve Nov 18, 2020 at 22:22

4 Answers 4

2

Consider something with nmap?

nmap -sP 10.1.2.0/24 10.2.5.0/24

It may be even simpler than a ping-loop, and it can scan multiple hosts in parallel so it'll appear much faster; but it will require the installation of nmap and its usual dependencies, and that may upset a resident security Oberleutnant fixated on the worst-case.

update: okay, Oberleutnanten for sure.

Instead:

xargs parallel -j20 ping -c1 -- | grep 'bytes from'

like

echo 10.0.{1..2}.{1..15} |\
  xargs parallel -j20 ping -c1 -- | grep 'bytes from'

64 bytes from 10.0.2.15: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from 10.0.2.3: icmp_seq=1 ttl=64 time=0.150 ms
64 bytes from 10.0.2.4: icmp_seq=1 ttl=64 time=0.176 ms
64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.138 ms

the time's good, too, as most of it is waiting for the pings to die at once. The positive results come back super fast:

$ time (echo 10.0.{1..2}.{1..15} | xargs parallel -j30 ping -c1 -- | grep 'bytes from')
64 bytes from 10.0.2.15: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from 10.0.2.3: icmp_seq=1 ttl=64 time=0.150 ms
64 bytes from 10.0.2.4: icmp_seq=1 ttl=64 time=0.176 ms
64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.138 ms

real    0m10.030s
user    0m0.019s
sys     0m0.018s

Swap out an arping and its particular parms for the ping if you wanna sniff winboxes too, as they hate pings.

Change out the cheesy grep for an awk '/bytes from/{print $4}' if you wanna get keen.

No bones about it, these other guys' ideas look like great quiz submissions and mine looks like banging nails with a screwdriver, but it's fast and simple.

2
  • Yeah I thought about nmap first but its a no go. I can use python or bash. Nov 18, 2020 at 22:09
  • Curses. Look into the parallel tool in the MoreUtils project to speed up the pings in parallel, then. And if python is your jam, totally consider using it. Nov 18, 2020 at 22:21
0

Something similar to this should help, add as many IP as you want to the list of ips:

#!/bin/bash

ips=(192.168.0.1 8.8.8.8 127.0.0.1)

here() {
    ping -c 1 $1 > /dev/null

    if [[ $? -eq 0 ]]
    then
        echo "Good morning, Here are the machines that are up and running: $i"
    fi

}

for i in ${ips[@]}

do here $i

done
2
  • 1
    Instead of individual variables, use an array: ips=(192.168.0.1 8.8.8.8 127.0.0.1 ...) then loop with for ip in "${ips[@]}"- you're allowed to put newlines and other arbitrary whitespace inside the parentheses of the array declaration, so it can be extremely readable. Nov 19, 2020 at 2:13
  • @glennjackman Thanks updated the answer!
    – Vombat
    Nov 19, 2020 at 9:12
0

How big is your IP range?

For a /24 consider

for i in {1..254} ; do
    if ping -c1 10.11.12.$i >/dev/null 2>/dev/null ; do
        echo "10.11.12.$i is up"
    else
        echo "10.11.12.$i is down
    fi
done

for a /16, you can add a second loop:

for j in {1..254} ; do
    for i in {1..254} ; do
        if ping -c1 10.11.$j.$i >/dev/null 2>/dev/null ; do
            echo "10.11.$j.$i is up"
        else
            echo "10.11.$j.$i is down
        fi
    done
done

And take a few cups of coffee waiting for it to finish.

But really nmap is the right tool.

1
  • I have 10 machines I need to make sure are up everyday. So it's by no means a big range. Nov 20, 2020 at 15:39
0

Here you are.

You can use like this:

./your_script_name.sh 192.168.1.0/24

#!/bin/bash

SUBNET=$1

if [[ -z "$SUBNET" ]]; then
    echo "Usage: ./your_script_name.sh <SUBNET>"
    exit
fi

printsubnet() {
        local OLDIFS="$IFS"
        local SUB=${1/\/*/}
        local MASK=$(( 1 << ( 32 - ${1/*\//} )))

        IFS="."
                set -- $SUB
                IPS=$((0x$(printf "%02x%02x%02x%02x\n" $1 $2 $3 $4)))
        IFS="$OLDIFS"

        for ((N=0; N<MASK; N++))
        {
                VAL=$((IPS|N))

                printf "%d.%d.%d.%d\n"                  \
                        $(( (VAL >> 24) & 255 ))        \
                        $(( (VAL >> 16) & 255 ))        \
                        $(( (VAL >> 8 ) & 255 ))        \
                        $(( (VAL)       & 255 ))
        }
}

mapfile IPS < <(printsubnet $SUBNET)

for row in "${IPS[@]}";do
        ping -c 1 "$row" >/dev/null 2>/dev/null
        if [ $? -eq 0 ]; then
                echo "$row is up"
        else
                echo "$row is down"
        fi
done
3
  • You might want mapfile -t to strip the newlines Nov 19, 2020 at 2:15
  • If you use local IFS=".", then you don't need to save the OLDIFS. Nov 19, 2020 at 2:16
  • I don't recall where I read this, but for ((...)) {...} with the braces is not recommended: use do...done Nov 19, 2020 at 2:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .