首页 > 解决方案 > 如何在 bash 脚本中使这些多个 Nmap 命令更优雅?

问题描述

我有一个我一直在处理的小型项目脚本,它会扫描我的网络以查找新的 MAC 地址,并在我的网络上是否有不熟悉的设备时通知我。

我已经介绍了在未知 MAC 地址(如果有)上自动执行操作系统扫描的功能。但是,我只能通过将 ping 扫描的 grepped 部分保存到一个临时文件 (tmpmac.txt) 中,然后将该文件中的 IP 地址 grep 到一个额外的临时文件 (tmpip.txt) 中来实现这一点,如-O Nmap 选项需要 IP 才能扫描:

        nmap -sn 192.168.0.0/24 | grep -B 2 "$address" > /home/pi/tmpmac.txt
        cat /home/pi/tmpmac.txt | grep "Nmap" | awk {'print $5'} > /home/pi/tmpip.txt
        unknown_mac=$( cat /home/pi/tmpip.txt )
        nmap -O $unknown_mac | tee -a /home/pi/mac_scan.log | mutt -s "OS Scan for $address" XXXXXXXX@gmail.com

整个脚本:

echo "<<---AUTOMATIC SCAN--->>" >>/home/pi/mac_scan.log
date >>/home/pi/mac_scan.log
nmap -sn 192.168.0.0/24 | grep "MAC" | awk '{print $3}'| sort > /home/pi/arp.txt

readarray -t mac </home/pi/arp.txt

foundall=true

for address in "${mac[@]}"; do
    if ! grep -Fxq "$address" /home/pi/arp_table.txt;
    then
        echo "WARNING: $address is an unknown device on the network" >> /home/pi/mac_scan.log
        nmap -sn 192.168.0.0/24 | grep -B 2 "$address" | tee -a /home/pi/mac_scan.log | mutt -s "Unknown Devices on Network" XXXXXXX@yahoo.com
        echo ""
        echo "MAC SEARCH RESULTS: $address" >> /home/pi/mac_scan.log
        nmap -sn 192.168.0.0/24 | grep -B 2 "$address" > /home/pi/tmpmac.txt
        cat /home/pi/tmpmac.txt | grep "Nmap" | awk {'print $5'} > /home/pi/tmpip.txt
        unknown_mac=$( cat /home/pi/tmpip.txt )
        nmap -O $unknown_mac | tee -a /home/pi/mac_scan.log | mutt -s "OS Scan for $address" XXXXXXXX@yahoo.com
        foundall=false
    fi
done

[[ "${foundall}" == 'true' ]] && echo "All Devices are familiar on your network" | tee -a /home/pi/mac_scan.log

当前形式的脚本执行其应有的方式,但我很好奇是否有更优雅的方式来实现这一点。

标签: bashnmaptee

解决方案


nmap的输出显然与你的不同,所以我无法对此进行测试,但我看不出有任何理由不跳过所有文件,并将整个管道放在一个var=$(command)结构中:

unknown_mac=$( nmap -sn 192.168.0.0/24 |
               grep -B 2 "$address" |
               grep "Nmap" |
               awk {'print $5'} )

但是,整个脚本会运行nmap -sn 192.168.0.0/24多次(开始时运行一次,然后每个新主机运行两次);为什么不一开始就将它存储在一个变量(或者可能是文件)中,然后在需要时使用它呢?

hostscan=$(nmap -sn 192.168.0.0/24)
...
echo "$hostscan" | othercommand
# or:
othercommand <<<"$hostscan"
# or if you prefer:
<<<"$hostscan" othercommand

请注意,在使用变量时双引号很重要。实际上,您几乎应该总是用双引号引用变量引用;有时您可以跳过双引号而侥幸,但了解何时安全比它的价值更麻烦。脚本中还有很多其他地方应该执行此操作。shellcheck.net擅长指出它们以及其他常见错误;我建议通过它运行您的脚本并修复它指出的内容。

你也可以折叠grep "somestring" | awk '{print $1}'到 just awk '/somestring/ {print $1}。通过所有这些更改,捕获未知 MAC 只是:

unknown_mac=$(<<<"$hostscan" grep -B 2 "$address" | awk '{/Nmap/ print $5}')

您还可以使用 here-string ( <<<) with readarray(注意:放在readarray管道的末尾是行不通的,因为管道中的东西在子外壳中运行):

readarray -t mac <<<"$(<<<"$hostscan" awk '/MAC/ {print $3}' | sort)"

推荐阅读