特定のネットワークに対し、疎通確認や稼働しているホストを確認する場合、よく以下のようなforを使用して確認処理を行うことがある。

for a in `seq 1 254`; do ping -c 1 -w 0.5 対象セグメント(第3オクテットまで).$a > /dev/null && arp -a 対象セグメント(第3オクテットまで).$a | grep ether; done

ただ、コレってやはりちょっと扱いにくい上、1個づつping打ってくからやっぱ遅い。 直接接続しているセグメントだったら、arp-scanだったりnmapだったり使えばすぐに取得できるのだが、その辺のコマンド入れてない(or入れられない)環境だったりした際に、コレをやるのはやはり面倒。 手打ちしたらtypoする長さだし。

で、そもそも今の時代だったら帯域も1Gbpsで構成されている場合が多い(古くてもまぁ100MBpsはあるでしょと)わけで、例えば一気に/24で254個分のping打ったところで、大した影響は無いだろうと(環境によっては瞬間的とはいえ、プロセスが254個増えるのはちょっと問題あるかもだけど)。 とは言え、ちょっとは気にしてpingで送るパケットサイズは最小にしておいた上で、以下のようにコマンドを実行して一気にpingを実行してやる。

pingや見やすくするために使っているsortのオプションがLinuxとBSD(Mac OS X)で違うので、それぞれで分けて記述しておく。 ついでに、timeコマンドで処理時間も計測。

Linuxの場合

echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -w1 | grep ttl | sort -V -k4
blacknon@BS-PUB-UBUNTU-01:~$ time (echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -w1 | grep ttl | sort -V -k4)
9 bytes from 192.168.0.1: icmp_seq=1 ttl=64
9 bytes from 192.168.0.12: icmp_seq=1 ttl=64
9 bytes from 192.168.0.14: icmp_seq=1 ttl=64
9 bytes from 192.168.0.20: icmp_seq=1 ttl=64
9 bytes from 192.168.0.42: icmp_seq=1 ttl=255
9 bytes from 192.168.0.43: icmp_seq=1 ttl=64
9 bytes from 192.168.0.53: icmp_seq=1 ttl=64
9 bytes from 192.168.0.102: icmp_seq=1 ttl=64
9 bytes from 192.168.0.104: icmp_seq=1 ttl=64
9 bytes from 192.168.0.106: icmp_seq=1 ttl=64
9 bytes from 192.168.0.107: icmp_seq=1 ttl=64
9 bytes from 192.168.0.117: icmp_seq=1 ttl=64
9 bytes from 192.168.0.118: icmp_seq=1 ttl=64
9 bytes from 192.168.0.119: icmp_seq=1 ttl=64
9 bytes from 192.168.0.120: icmp_seq=1 ttl=64
9 bytes from 192.168.0.121: icmp_seq=1 ttl=64
9 bytes from 192.168.0.132: icmp_seq=1 ttl=64
9 bytes from 192.168.0.133: icmp_seq=1 ttl=64
9 bytes from 192.168.0.134: icmp_seq=1 ttl=64
9 bytes from 192.168.0.169: icmp_seq=1 ttl=64
9 bytes from 192.168.0.170: icmp_seq=1 ttl=64
9 bytes from 192.168.0.171: icmp_seq=1 ttl=64
9 bytes from 192.168.0.176: icmp_seq=1 ttl=64
9 bytes from 192.168.0.187: icmp_seq=1 ttl=64
9 bytes from 192.168.0.194: icmp_seq=1 ttl=64
9 bytes from 192.168.0.195: icmp_seq=1 ttl=64
9 bytes from 192.168.0.196: icmp_seq=1 ttl=64
9 bytes from 192.168.0.197: icmp_seq=1 ttl=64
9 bytes from 192.168.0.198: icmp_seq=1 ttl=64
9 bytes from 192.168.0.199: icmp_seq=1 ttl=64
9 bytes from 192.168.0.201: icmp_seq=1 ttl=64
9 bytes from 192.168.0.203: icmp_seq=1 ttl=64
9 bytes from 192.168.0.204: icmp_seq=1 ttl=64
9 bytes from 192.168.0.205: icmp_seq=1 ttl=64
9 bytes from 192.168.0.230: icmp_seq=1 ttl=64

real    0m1.268s
user    0m0.008s
sys     0m0.072s

Mac OS Xの場合

echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -W1 | grep ttl | gsort -V -k4 # gsort利用
echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -W1 | grep ttl | sort -t'.' -k1,1n -k2,2n -k3,3n -k4,4n 
blacknon@BS-PUB-UBUNTU-01:~$ time (echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -w1 | grep ttl | sort -V -k4)
9 bytes from 192.168.0.1: icmp_seq=1 ttl=64
9 bytes from 192.168.0.12: icmp_seq=1 ttl=64
9 bytes from 192.168.0.14: icmp_seq=1 ttl=64
9 bytes from 192.168.0.20: icmp_seq=1 ttl=64
9 bytes from 192.168.0.42: icmp_seq=1 ttl=255
9 bytes from 192.168.0.43: icmp_seq=1 ttl=64
9 bytes from 192.168.0.53: icmp_seq=1 ttl=64
9 bytes from 192.168.0.102: icmp_seq=1 ttl=64
9 bytes from 192.168.0.104: icmp_seq=1 ttl=64
9 bytes from 192.168.0.106: icmp_seq=1 ttl=64
9 bytes from 192.168.0.107: icmp_seq=1 ttl=64
9 bytes from 192.168.0.117: icmp_seq=1 ttl=64
9 bytes from 192.168.0.118: icmp_seq=1 ttl=64
9 bytes from 192.168.0.119: icmp_seq=1 ttl=64
9 bytes from 192.168.0.120: icmp_seq=1 ttl=64
9 bytes from 192.168.0.121: icmp_seq=1 ttl=64
9 bytes from 192.168.0.132: icmp_seq=1 ttl=64
9 bytes from 192.168.0.133: icmp_seq=1 ttl=64
9 bytes from 192.168.0.134: icmp_seq=1 ttl=64
9 bytes from 192.168.0.169: icmp_seq=1 ttl=64
9 bytes from 192.168.0.170: icmp_seq=1 ttl=64
9 bytes from 192.168.0.171: icmp_seq=1 ttl=64
9 bytes from 192.168.0.176: icmp_seq=1 ttl=64
9 bytes from 192.168.0.187: icmp_seq=1 ttl=64
9 bytes from 192.168.0.194: icmp_seq=1 ttl=64
9 bytes from 192.168.0.195: icmp_seq=1 ttl=64
9 bytes from 192.168.0.196: icmp_seq=1 ttl=64
9 bytes from 192.168.0.197: icmp_seq=1 ttl=64
9 bytes from 192.168.0.198: icmp_seq=1 ttl=64
9 bytes from 192.168.0.199: icmp_seq=1 ttl=64
9 bytes from 192.168.0.201: icmp_seq=1 ttl=64
9 bytes from 192.168.0.203: icmp_seq=1 ttl=64
9 bytes from 192.168.0.204: icmp_seq=1 ttl=64
9 bytes from 192.168.0.205: icmp_seq=1 ttl=64
9 bytes from 192.168.0.230: icmp_seq=1 ttl=64

real    0m1.268s
user    0m0.008s
sys     0m0.072s
blacknon@BS-PUB-UBUNTU-01:~$ time (echo 192.168.0.{1..254} | xargs -P254 -n1 ping -s1 -c1 -W1 | grep ttl | sort -t'.' -k1,1n -k2,2n -k3,3n -k4,4n )
9 bytes from 192.168.0.1: icmp_seq=1 ttl=64
9 bytes from 192.168.0.12: icmp_seq=1 ttl=64
9 bytes from 192.168.0.14: icmp_seq=1 ttl=64
9 bytes from 192.168.0.20: icmp_seq=1 ttl=64
9 bytes from 192.168.0.42: icmp_seq=1 ttl=255
9 bytes from 192.168.0.43: icmp_seq=1 ttl=64
9 bytes from 192.168.0.53: icmp_seq=1 ttl=64
9 bytes from 192.168.0.102: icmp_seq=1 ttl=64
9 bytes from 192.168.0.104: icmp_seq=1 ttl=64
9 bytes from 192.168.0.106: icmp_seq=1 ttl=64
9 bytes from 192.168.0.107: icmp_seq=1 ttl=64
9 bytes from 192.168.0.117: icmp_seq=1 ttl=64
9 bytes from 192.168.0.118: icmp_seq=1 ttl=64
9 bytes from 192.168.0.119: icmp_seq=1 ttl=64
9 bytes from 192.168.0.120: icmp_seq=1 ttl=64
9 bytes from 192.168.0.121: icmp_seq=1 ttl=64
9 bytes from 192.168.0.132: icmp_seq=1 ttl=64
9 bytes from 192.168.0.133: icmp_seq=1 ttl=64
9 bytes from 192.168.0.134: icmp_seq=1 ttl=64
9 bytes from 192.168.0.169: icmp_seq=1 ttl=64
9 bytes from 192.168.0.170: icmp_seq=1 ttl=64
9 bytes from 192.168.0.171: icmp_seq=1 ttl=64
9 bytes from 192.168.0.176: icmp_seq=1 ttl=64
9 bytes from 192.168.0.187: icmp_seq=1 ttl=64
9 bytes from 192.168.0.194: icmp_seq=1 ttl=64
9 bytes from 192.168.0.195: icmp_seq=1 ttl=64
9 bytes from 192.168.0.196: icmp_seq=1 ttl=64
9 bytes from 192.168.0.197: icmp_seq=1 ttl=64
9 bytes from 192.168.0.198: icmp_seq=1 ttl=64
9 bytes from 192.168.0.199: icmp_seq=1 ttl=64
9 bytes from 192.168.0.201: icmp_seq=1 ttl=64
9 bytes from 192.168.0.203: icmp_seq=1 ttl=64
9 bytes from 192.168.0.204: icmp_seq=1 ttl=64
9 bytes from 192.168.0.205: icmp_seq=1 ttl=64
9 bytes from 192.168.0.230: icmp_seq=1 ttl=64

real    0m1.244s
user    0m0.000s
sys     0m0.076s

計測結果を見るとわかるように、1秒ほどで254台に対して疎通確認を行うことができた。 ちなみに、このやり方だとTTLも確認ができるので、対象のIPアドレスのOSが何を使ってるのかについても大体推測ができる(64だとLinux、124だとWindows、256だとUNIX系と推測できる)。


番外編

MacやLinuxはこれで良いとして、Windowsではどうすればいいか。

とりあえず、Windows 10であればBash on Windowsの機能を利用すれば同じことができるだろう(中身Ubuntuだし)。 もしくは、PowerShell 3以降が入っているようなら、以下のようにコマンドを実行することで(ちょっと遅い+長いけど)pingをパラレルに実行できそうだ。

PowerShellでパラレルでのコマンド実行を行う場合、どうもwordkflowとして定義が必要になるらしいので、このような形になった。もっと良い書き方ありそうなもんだけど…

workflow x{foreach -parallel($a in 1..254) {ping -l 1 -n 1 -w 10 172.20.100.$a}};x