Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write a Linux bash script that tells me which computers are ON in my LAN?

Tags:

linux

bash

ping

How can I write a Linux Bash script that tells me which computers are ON in my LAN?

It would help if I could give it a range of IP addresses as input.

like image 566
Dumb Questioner Avatar asked Apr 09 '09 09:04

Dumb Questioner


People also ask

Which command would you use in Linux to check the availability of another machine in a LAN?

How ping Works in Linux. The Linux ping command is a simple utility used to check whether a network is available and if a host is reachable.


1 Answers

I would suggest using nmap's ping-scan flag,

$ nmap -sn 192.168.1.60-70  Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2009-04-09 20:13 BST Host machine1.home (192.168.1.64) appears to be up. Host machine2.home (192.168.1.65) appears to be up. Nmap finished: 11 IP addresses (2 hosts up) scanned in 0.235 seconds 

That said, if you want to write it yourself (which is fair enough), this is how I would do it:

for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done 

..and an explanation of each bit of the above command:

Generating list of IP addresses

You can use the {1..10} syntax to generate a list of numbers, for example..

$ echo {1..10} 1 2 3 4 5 6 7 8 9 10 

(it's also useful for things like mkdir {dir1,dir2}/{sub1,sub2} - which makes dir1 and dir2, each containing sub1 and sub2)

So, to generate a list of IP's, we'd do something like

$ echo 192.168.1.{1..10} 192.168.1.1 192.168.1.2 [...] 192.168.1.10 

Loops

To loop over something in bash, you use for:

$ for thingy in 1 2 3; do echo $thingy; done 1 2 3 

Pinging

Next, to ping.. The ping command varies a bit with different operating-systems, different distributions/versions (I'm using OS X currently)

By default (again, on the OS X version of ping) it will ping until interrupted, which isn't going to work for this, so ping -c 1 will only try sending one packet, which should be enough to determine if a machine is up.

Another problem is the timeout value, which seems to be 11 seconds on this version of ping.. It's changed using the -t flag. One second should be enough to see if a machine on the local network is alive or not.

So, the ping command we'll use is..

$ ping -c 1 -t 1 192.168.1.1 PING 192.168.1.1 (192.168.1.1): 56 data bytes  --- 192.168.1.1 ping statistics --- 1 packets transmitted, 0 packets received, 100% packet loss 

Checking ping result

Next, we need to know if the machine replied or not..

We can use the && operator to run a command if the first succeeds, for example:

$ echo && echo "It works"  It works $ nonexistantcommand && echo "This should not echo" -bash: nonexistantcommand: command not found 

Good, so we can do..

ping -c 1 -t 1 192.168.1.1 && echo "192.168.1.1 is up!"

The other way would be to use the exit code from ping.. The ping command will exit with exit-code 0 (success) if it worked, and a non-zero code if it failed. In bash you get the last commands exit code with the variable $?

So, to check if the command worked, we'd do..

ping -c 1 -t 1 192.168.1.1; if [ $? -eq 0 ]; then     echo "192.168.1.1 is up"; else      echo "ip is down"; fi 

Hiding ping output

Last thing, we don't need to see the ping output, so we can redirect stdout to /dev/null with the > redirection, for example:

$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up" IP is up 

And to redirect stderr (to discard the ping: sendto: Host is down messages), you use 2> - for example:

$ errorcausingcommand -bash: errorcausingcommand: command not found $ errorcausingcommand 2> /dev/null $ 

The script

So, to combine all that..

for ip in 192.168.1.{1..10}; do  # for loop and the {} operator     ping -c 1 -t 1 192.168.1.1 > /dev/null 2> /dev/null  # ping and discard output     if [ $? -eq 0 ]; then  # check the exit code         echo "${ip} is up" # display the output         # you could send this to a log file by using the >>pinglog.txt redirect     else         echo "${ip} is down"     fi done 

Or, using the && method, in a one-liner:

for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done 

Problem

It's slow.. Each ping command takes about 1 second (since we set the -t timeout flag to 1 second). It can only run one ping command at a time.. The obvious way around this is to use threads, so you can run concurrent commands, but that's beyond what you should use bash for..

"Python threads - a first example" explains how to use the Python threading module to write a multi-threaded ping'er.. Although at that point, I would once again suggest using nmap -sn..

like image 160
dbr Avatar answered Sep 20 '22 20:09

dbr