【问题标题】:How do I make these multiple Nmap commands more elegant in bash script?如何在 bash 脚本中使这些多个 Nmap 命令更优雅?
【发布时间】:2021-11-05 16:45:22
【问题描述】:

我一直在编写一个小型项目脚本,它会扫描我的网络以查找新的 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

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

【问题讨论】:

    标签: bash nmap tee


    【解决方案1】:

    我的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
    

    请注意,在使用变量时双引号很重要。实际上,您几乎应该总是用双引号引用变量引用;你有时可以跳过双引号,但understanding when it's safe is more trouble than it's worth。脚本中还有很多其他地方应该执行此操作。 shellcheck.net 善于指出它们以及其他常见错误;我建议通过它运行您的脚本并修复它指出的内容。

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

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

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

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

    【讨论】:

    • 非常感谢戈登。这正是我想要的。