Je suggérerais d'utiliser le drapeau ping-scan de 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
Cela dit, si vous voulez l'écrire vous-même (ce qui est assez juste), voici comment je procéderais :
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
..et une explication de chaque bit de la commande ci-dessus :
Génération d'une liste d'adresses IP
Vous pouvez utiliser le {1..10}
syntaxe pour générer une liste de nombres, par exemple..
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
(c'est aussi utile pour des choses comme mkdir {dir1,dir2}/{sub1,sub2}
- ce qui fait dir1
et dir2
, contenant chacun sub1
et sub2
)
Donc, pour générer une liste d'adresses IP, nous ferions quelque chose comme
$ echo 192.168.1.{1..10}
192.168.1.1 192.168.1.2 [...] 192.168.1.10
Boucles
Pour boucler quelque chose dans bash, vous utilisez for
:
$ for thingy in 1 2 3; do echo $thingy; done
1
2
3
Pinging
Ensuite, pour ping.. La commande ping varie un peu avec différents systèmes d'exploitation, différentes distributions/versions (j'utilise OS X actuellement)
Par défaut (encore une fois, sur la version OS X de ping
) il fera un ping jusqu'à ce qu'il soit interrompu, ce qui ne fonctionnera pas pour cela, donc ping -c 1
n'essaiera d'envoyer qu'un seul paquet, ce qui devrait être suffisant pour déterminer si une machine est en marche.
Un autre problème est la valeur du délai d'attente, qui semble être de 11 secondes sur cette version de ping. Elle est modifiée en utilisant le -t
drapeau. Une seconde devrait suffire pour voir si une machine sur le réseau local est active ou non.
Donc, la commande ping que nous allons utiliser est...
$ 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
Vérification du résultat du ping
Ensuite, nous devons savoir si la machine a répondu ou non..
Nous pouvons utiliser le &&
opérateur pour exécuter une commande si la première réussit, par exemple :
$ echo && echo "It works"
It works
$ nonexistantcommand && echo "This should not echo"
-bash: nonexistantcommand: command not found
Bon, donc on peut faire..
ping -c 1 -t 1 192.168.1.1 &&echo "192.168.1.1 est actif !"
L'autre façon serait d'utiliser le code de sortie de ping. La commande ping se terminera avec le code de sortie 0 (succès) si cela a fonctionné, et un code non nul si cela a échoué. En bash, vous obtenez le code de sortie des dernières commandes avec la variable $?
Donc, pour vérifier si la commande a fonctionné, nous ferions...
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
Masquer la sortie du ping
Dernière chose, nous n'avons pas besoin de voir la sortie du ping, nous pouvons donc rediriger stdout
à /dev/null
avec le >
redirection, par exemple :
$ ping -c 1 -t 1 192.168.1.1 > /dev/null && echo "IP is up"
IP is up
Et pour rediriger stderr
(pour supprimer le ping: sendto: Host is down
messages), vous utilisez 2>
- par exemple :
$ errorcausingcommand
-bash: errorcausingcommand: command not found
$ errorcausingcommand 2> /dev/null
$
Le scénario
Alors, pour combiner tout ça..
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
Ou, en utilisant le &&
méthode, dans un one-liner :
for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
Problème
C'est lent. Chaque commande ping prend environ 1 seconde (puisque nous avons défini l'indicateur de délai d'attente -t sur 1 seconde). Il ne peut exécuter qu'une seule commande ping à la fois. La solution évidente consiste à utiliser des threads, afin que vous puissiez exécuter des commandes simultanées, mais cela va au-delà de ce pour quoi vous devriez utiliser bash..
"Threads Python - un premier exemple" explique comment utiliser le module de threading Python pour écrire un ping'er multi-thread. Bien qu'à ce stade, je suggérerais à nouveau d'utiliser nmap -sn
..
Dans le monde réel, vous pourriez utiliser nmap pour obtenir ce que vous voulez.
nmap -sn 10.1.1.1-255
Cela enverra un ping à toutes les adresses de la plage 10.1.1.1 à 10.1.1.255 et vous indiquera celles qui répondent.
Bien sûr, si vous voulez en fait faire cela comme un exercice bash, vous pouvez exécuter ping pour chaque adresse et analyser la sortie, mais c'est une toute autre histoire.
En supposant que mon réseau est 10.10.0.0/24, si je lance un ping sur l'adresse de diffusion comme
ping -b 10.10.0.255
J'obtiendrai une réponse de tous les ordinateurs de ce réseau qui n'ont pas bloqué leur port 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
Il vous suffit donc d'extraire la 4ème colonne, avec awk par exemple :
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:
Eh bien, vous obtiendrez un doublon et vous devrez peut-être supprimer le ':'.
EDIT depuis les commentaires :l'option -c limite le nombre de pings puisque le script va se terminer, on peut aussi se limiter aux IP uniques
ping -c 5 -b 10.10.0.255 | grep 'bytes from' | awk '{ print $4 }' | sort | uniq