For the punters out there... think you can find a better (shorter command line? no signals?) way to solve this interesting problem?
I want to run an nmap on a network range, but have it quit (with output) the instant it finds the first "up" host. Nmap doesn't seem to have any way to achieve this. So I thought why not use unix pipes to do this?
Oh ya, let's throw on a maximum run time too. So the goal is to run as quickly as we can to find one host on the network (the normal case), with the total time capped at something lower than nmap seems to want to take.
And I need a way to still tell if the whole enchilada found something or not, and I want to wait for that result to come in. I need to take different action on whether we found a host or not.
Note, nmap timeout and rtt options seem to apply per-host so even with sane-ish numbers, nmap will still often take 40-60s to run this command.
Here's what I've come up with (view in monospace):
echo 192.168.101 | \ timeout 30 bash -c \ " \ sint=$(cat); \ (nmap -ddd -vvv --send-ip \ --host-timeout 5s --max-rtt-timeout 1s --initial-rtt-timeout 500ms \ --max-retries 1 -S $sint.1 -sn -PE $sint.2 $sint.254-254 2>&1 & \ echo $! >&3) \ 3>pidnmap \ | grep --line-buffered -P 'RCVD.{0,30}?ICMP.{0,60}?Echo reply' \ | (head -1 && kill $(<pidnmap) 2>&1) \ " \ |grep RCVD || echo "no hosts found"
I initially thought head would sigpipe the nmap once it got it's one line... and maybe it is, but nmap doesn't quit. So I have to explicitly kill the nmap later to make sure it truly dies rather than continue its 60s run. Hence the convoluted pid/kill stuff. I tried pkill -g0 at first, but it ate all the output and made it impossible to tell if we got output or not. And using return values (ideal) seems completely hopeless as soon as signals are involved.
And no, setting /bin/timeout to the very minimum time I'm willing to tolerate (say 10s?) is not a good solution either, as I really want this command to return in the < 100ms it takes in the normal case.
So, other than hacking nmap to immediately respond to sigpipe or adding a "quit after finding X up hosts" option, does anyone see a better UNIXy way to do this? The general problem isn't nmap specific... it's really a problem of shortcircuiting out of any long-running program when we see a certain line of its output. Heck, maybe there's already a coreutil or moreutil that does this generally somehow, but I couldn't find it faster than I could write the above!
My gut says it's just got to be easier than this!! I couldn't believe how convoluted the solution quickly became.