Or should I just ditch the bash script for a Python script?
Yes :-)
If you want to use bash, you could parse the file, sort it, then present it like this:
while read -r line; do if grep -q 'Nmap scan report for' <<<"$line"; then ip=$(sed 's/Nmap scan report for //' <<<"$line"); elif grep -q 'MAC Address' <<<"$line"; then mac=$(sed 's/MAC Address: //' <<<"$line") echo "$ip $mac" >> tmp1-$$ fi done sort -k 2 tmp1-$$ > tmp2-$$ lastmac='' while read -r line; do ip="$(sed 's/ .*//' <<<"$line")" mac="$(sed -E 's/^[^ ]+ //' <<<"$line")" if [ "$lastmac" != "$mac" ]; then echo "MAC Address: $mac" fi echo "IP Address: $ip" lastmac=$mac done <tmp2-$$ rm tmp1-$$ tmp2-$$
You could improve that by using bash 4 associate arrays rather than the intermediate files:
#!/bin/bash declare -A arr while read -r line; do if grep -q 'Nmap scan report for' <<<"$line"; then ip=$(sed 's/Nmap scan report for //' <<<"$line"); elif grep -q 'MAC Address' <<<"$line"; then mac=$(sed 's/MAC Address: //' <<<"$line") arr["$mac"]="${arr["$mac"]} $ip" fi done for mac in "${!arr[@]}"; do printf "MAC Address: $mac\n" for ip in ${arr["$mac"]}; do printf "IP Address: $ip\n" done done
If you prefer pipes to code, you could hack something like this:
<input (grep -E '(MAC Address|Nmap scan report for)' | sed -E -e 's/MAC Address: (.*)/\1 END/' -e 's/Nmap scan report for (.*)/\1 /' | tr -d '\n') |sed 's/ END/\n/g' | sort -k 2 > a <a sed -E -e 's/^[^ ]+ //' | uniq | xargs -d '\n' -n 1 -I {} bash -c "echo 'MAC Address: {} '; grep '{}' a|sed -e 's/ .*//' -e 's/^/IP Address: /'"
But it’s all pretty awful. I’m sure there somewhat better perl / awk ways to do it too.
I’d run Nmap with `-oX n.xml` then use some python like:
""" parse output of sudo nmap -sP 192.168.70.0/24 -oX - >n.xml """ import xml.etree.ElementTree as ET ROOT = ET.parse('n.xml').getroot() IPV4S = {} VENDORS = {} for h in ROOT.findall('host'): mac = None ipv4 = None vendor = 'unknown' for address in h.findall('address'): addrtype = address.attrib['addrtype'] if addrtype == "mac": mac = address.attrib['addr'] vendor = address.attrib['vendor'] elif addrtype == "ipv4": ipv4 = address.attrib['addr'] # print "mac={},ipv4={}".format(mac,ipv4) if mac in IPV4S: IPV4S[mac].append(ipv4) else: IPV4S[mac] = [ipv4] if mac not in VENDORS: VENDORS[mac] = vendor
for mac in IPV4S: print "MAC Address: {} ({})".format(mac, VENDORS[mac]) print '\n'.join([" IP Address: {}".format(x) for x in IPV4S[mac]])
That way the parsing is more solid, and you can deal with edge cases better, and when you look at it in a few months it’s easier to see what’s going on.
— Martijn
On 29 Jul 2019, at 13:44, Mark Rogers mark@more-solutions.co.uk wrote:
I have a simple bash script for locating Raspberry Pis on the network:
#!/bin/bash PIMAC=B8:27:EB sudo nmap -sP 192.168.251.0/24 | grep -i " $PIMAC" -A0 -B2
Whilst the output gives me the answer I want I'd like to tidy up the formatting. The current result is:
Nmap scan report for 192.168.10.20 Host is up (-0.10s latency). MAC Address: B8:27:EB:22:1C:05 (Raspberry Pi Foundation) -- Nmap scan report for 192.168.10.24 Host is up (-0.10s latency). MAC Address: B8:27:EB:22:1C:05 (Raspberry Pi Foundation)
What I want out of it is something more like: MAC Address: B8:27:EB:22:1C:05 (Raspberry Pi Foundation) IP Address: 192.168.10.20 IP Address: 192.168.10.24
What is the best way to do this? Or should I just ditch the bash script for a Python script?
-- Mark Rogers // More Solutions Ltd (Peterborough Office) // 0844 251 1450 Registered in England (0456 0902) 21 Drakes Mews, Milton Keynes, MK8 0ER
main@lists.alug.org.uk http://www.alug.org.uk/ https://lists.alug.org.uk/mailman/listinfo/main Unsubscribe? See message headers or the web site above!