Suggerirei di usare il flag ping-scan di nmap,
$ 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
Detto questo, se vuoi scriverlo tu stesso (il che è abbastanza giusto), ecco come lo farei:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
..e una spiegazione di ogni bit del comando precedente:
Generazione elenco di indirizzi IP
Puoi usare il {1..10}
sintassi per generare un elenco di numeri, ad esempio...
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
(è anche utile per cose come mkdir {dir1,dir2}/{sub1,sub2}
- che fa dir1
e dir2
, ciascuno contenente sub1
e sub2
)
Quindi, per generare un elenco di IP, faremmo qualcosa del genere
$ echo 192.168.1.{1..10}
192.168.1.1 192.168.1.2 [...] 192.168.1.10
Loop
Per eseguire il loop su qualcosa in bash, si usa for
:
$ for thingy in 1 2 3; do echo $thingy; done
1
2
3
Ping
Successivamente, ping.. Il comando ping varia leggermente con diversi sistemi operativi, diverse distribuzioni/versioni (attualmente sto usando OS X)
Per impostazione predefinita (di nuovo, nella versione OS X di ping
) eseguirà il ping fino a quando non verrà interrotto, il che non funzionerà per questo, quindi ping -c 1
tenterà di inviare solo un pacchetto, che dovrebbe essere sufficiente per determinare se una macchina è attiva.
Un altro problema è il valore di timeout, che sembra essere di 11 secondi su questa versione di ping.. È cambiato usando -t
bandiera. Un secondo dovrebbe essere sufficiente per vedere se una macchina sulla rete locale è attiva o meno.
Quindi, il comando ping che useremo è..
$ 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
Controllo del risultato del ping
Successivamente, dobbiamo sapere se la macchina ha risposto o meno..
Possiamo usare il &&
operatore per eseguire un comando se il primo ha esito positivo, ad esempio:
$ echo && echo "It works"
It works
$ nonexistantcommand && echo "This should not echo"
-bash: nonexistantcommand: command not found
Bene, quindi possiamo fare...
ping -c 1 -t 1 192.168.1.1 &&echo "192.168.1.1 è attivo!"
L'altro modo sarebbe utilizzare il codice di uscita da ping.. Il comando ping terminerà con il codice di uscita 0 (successo) se ha funzionato e un codice diverso da zero se ha avuto esito negativo. In bash ottieni il codice di uscita degli ultimi comandi con la variabile $?
Quindi, per verificare se il comando ha funzionato, faremmo...
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
Nascondere l'output del ping
Ultima cosa, non abbiamo bisogno di vedere l'output del ping, quindi possiamo reindirizzare stdout
a /dev/null
con il >
reindirizzamento, ad esempio:
$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up"
IP is up
E per reindirizzare stderr
(per eliminare il ping: sendto: Host is down
messaggi), usi 2>
- ad esempio:
$ errorcausingcommand
-bash: errorcausingcommand: command not found
$ errorcausingcommand 2> /dev/null
$
Il copione
Quindi, per combinare tutto questo...
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
Oppure, usando il &&
metodo, in una riga:
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
Problema
È lento... Ogni comando ping richiede circa 1 secondo (poiché abbiamo impostato il flag -t timeout su 1 secondo). Può eseguire solo un comando ping alla volta.. Il modo ovvio per aggirare questo è usare i thread, in modo da poter eseguire comandi simultanei, ma questo va oltre ciò per cui dovresti usare bash..
"Python threads - a first example" spiega come usare il modulo Python threading per scrivere un ping'er multi-thread. Anche se a quel punto, suggerirei ancora una volta di usare nmap -sn
..
Nel mondo reale, potresti usare nmap per ottenere quello che vuoi.
nmap -sn 10.1.1.1-255
Questo eseguirà il ping di tutti gli indirizzi nell'intervallo da 10.1.1.1 a 10.1.1.255 e ti farà sapere quali rispondono.
Ovviamente, se in realtà vuoi farlo come esercizio di bash, puoi eseguire il ping per ogni indirizzo e analizzare l'output, ma questa è tutta un'altra storia.
Supponendo che la mia rete sia 10.10.0.0/24, se eseguo un ping sull'indirizzo di trasmissione come
ping -b 10.10.0.255
Riceverò una risposta da tutti i computer su questa rete che non hanno bloccato la loro porta ping ICMP.
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
Quindi devi solo estrarre la quarta colonna, con awk per esempio:
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:
Bene, otterrai un duplicato e potresti dover rimuovere ':'.
EDIT dai commenti:l'opzione -c limita il numero di ping poiché lo script terminerà, possiamo anche limitarci su IP univoci
ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }' | sort | uniq