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

前端 未结 16 1428
攒了一身酷
攒了一身酷 2020-12-12 11:59

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.

相关标签:
16条回答
  • 2020-12-12 12:45

    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..

    0 讨论(0)
  • 2020-12-12 12:48

    If you want to provide a list of hosts it can be done with nmap, grep and awk.

    Install nmap:

    $ sudo apt-get install nmap
    

    Create file hostcheck.sh like this:

    hostcheck.sh

    #!/bin/bash
    
    nmap -sP -iL hostlist -oG pingscan > /dev/null
    grep Up pingscan | awk '{print $2}' > uplist
    grep Down pingscan | awk '{print $2}' > downlist
    

    -sP: Ping Scan - go no further than determining if host is online

    -iL : Input from list of hosts/networks

    -oG : Output scan results in Grepable format, to the given filename.

    /dev/null : Discards output

    Change the access permission:

    $ chmod 775 hostcheck.sh
    

    Create file hostlist with the list of hosts to be checked (hostname or IP):

    hostlist (Example)

    192.168.1.1-5
    192.168.1.101
    192.168.1.123
    

    192.168.1.1-5 is a range of IPs

    Run the script:

    ./hostcheck.sh hostfile

    Will be generated files pingscan with all the information, uplist with the hosts online (Up) and downlist with the hosts offline (Down).

    uplist (Example)

    192.168.1.1
    192.168.1.2
    192.168.1.3
    192.168.1.4
    192.168.1.101
    

    downlist (Example)

    192.168.1.5
    192.168.1.123
    
    0 讨论(0)
  • 2020-12-12 12:53

    Well, this is part of a script of mine.

    ship.sh

    0 讨论(0)
  • 2020-12-12 12:55

    As other posters pointed out, nmap is the way to go, but here's how to do the equivalent of a ping scan in bash. I wouldn't use the broadcast ping, as a lot of systems are configured not to respond to broadcast ICMP nowadays.

    for i in $(seq 1 254); do
        host="192.168.100.$i"
        ping -c 1 -W 1 $host &> /dev/null
        echo -n "Host $host is "
        test $? -eq 0 && echo "up" || echo "down"
    done
    
    0 讨论(0)
  • 2020-12-12 12:56

    Assuming my network is 10.10.0.0/24, if i run a ping on the broadcast address like

    ping -b 10.10.0.255
    

    I'll get an answer from all computers on this network that did not block their ICMP ping port.

    64 bytes from 10.10.0.6: icmp_seq=1 ttl=64 time=0.000 ms
    64 bytes from 10.10.0.12: icmp_seq=1 ttl=64 time=0.000 ms 
    64 bytes from 10.10.0.71: icmp_seq=1 ttl=255 time=0.000 ms 
    

    So you just have to extract the 4th column, with awk for example:

    ping -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }'
    
    10.10.0.12:
    10.10.0.6:
    10.10.0.71:
    10.10.0.95:
    

    Well, you will get duplicate, and you may need to remove the ':'.

    EDIT from comments : the -c option limits the number of pings since the script will end, we can also limit ourself on unique IPs

    ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }' | sort | uniq
    
    0 讨论(0)
  • 2020-12-12 13:00
    • ip neighbor
    • arp -a
    • Arpwatch
    0 讨论(0)
提交回复
热议问题