【问题标题】:Parse a dhcpd.lease File with Bash使用 Bash 解析 dhcpd.lease 文件
【发布时间】:2021-01-24 16:08:31
【问题描述】:

我尝试使用 Basel 解析我的 dhcpd.lease 文件。一个典型的条目如下所示:

lease 192.168.20.4 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
    uid 00:00:00:00:00:00;
    client-hostname "examle-workstation1";
}

我得到的所有信息都是 MAC,我想要的是 IP 和客户端主机名。但也许,没有客户端主机名。条目如下所示:

lease 192.168.20.5 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
}

我的第一个想法是 grep 租用属性、硬件以太网属性和 uid 属性并将它们全部放在一条线上。然后解析它。

但我的问题是,我有一个大文件,在许多文件中分配了许多条目。树看起来像这样:

dhcpd-leases
-- 192.168.20.0
-- 192.168.30.0
-- 192.168.40.0
[...]

我得到的所有信息都是从另一个文件解析到一个列表中的 MAC。所以我从这个列表开始,想用我的 MAC grep 属性 ip,mac:

for ENTRY in $MACLIST
do
    VAR$(cat "dhcpd-leases/10.148.$NETWORK.2/dhcpd.leases" | grep -E "$MAC|lease|client-hostname")
    echo $VAR
done

但由于 $VAR 中有许多条目,并且文件无法正确解析。

有人可以帮忙吗?

最好的问候 彼得

【问题讨论】:

    标签: bash parsing grep


    【解决方案1】:

    假设你的 maclist 文件看起来像这样(例如只有一个条目)

    $ cat maclist
    00:00:00:00:00:01
    

    你的租约文件是这样的

    $ cat file
    lease 192.168.20.4 {
        starts 6 2009/06/27 00:40:00;
        ends 6 2009/06/27 12:40:00;
        hardware ethernet 00:00:00:00:00:00;
        uid 00:00:00:00:00:00;
        client-hostname "examle-workstation1";
    }
    
    lease 192.168.20.5 {
        starts 6 2009/06/27 00:40:00;
        ends 6 2009/06/27 12:40:00;
        hardware ethernet 00:00:00:00:00:00;
    }
    
    lease 192.168.20.6 {
        starts 6 2009/06/27 00:40:00;
        ends 6 2009/06/27 12:40:00;
        hardware ethernet 00:00:00:00:00:01;
        uid 00:00:00:00:00:01;
        client-hostname "examle-workstation2";
    }
    
    
    lease 192.168.20.7 {
        starts 6 2009/06/27 00:40:00;
        ends 6 2009/06/27 12:40:00;
        hardware ethernet 01:00:00:00:00:00;
    }
    

    你可以试试这个

    awk 'BEGIN{
        while( (getline line < "maclist") > 0){
            mac[line]
        }
        RS="}"
        FS="\n"
    }
    /lease/{
        for(i=1;i<=NF;i++){
            gsub(";","",$i)
            if ($i ~ /lease/) {
                m=split($i, IP," ")
                ip=IP[2]
            }
            if( $i ~ /hardware/ ){
                m=split($i, hw," ")
                ether=hw[3]
            }
            if ( $i ~ /client-hostname/){
                m=split($i,ch, " ")
                hostname=ch[2]
            }
            if ( $i ~ /uid/){
                m=split($i,ui, " ")
                uid=ui[2]
            }
        }
        if ( ether in mac ){
            print "ip: "ip " hostname: "hostname " ether: "ether " uid: "uid
        }
    } ' file
    

    输出

    $ ./shell.sh
    hostname: "examle-workstation2" ether: 00:00:00:00:00:01 uid: 00:00:00:00:00:01
    

    【讨论】:

      【解决方案2】:

      我喜欢 awk,但当程序变大时我不喜欢它。

      所以我找到了另一种解析租约文件的方法,首先找到一个将文件转换为两列格式的unix命令链,第一列是ip地址,第二列是mac地址:

      egrep -o 'lease.*{|ethernet.*;' dhcpd.leases | awk '{print $2}' | xargs -n 2 | cut -d ';' -f 1
      

      使用简单的 awk 命令,您就可以从 mac 地址获取 IP 地址。以下是构建为 shell 函数的完整命令:

      function f_mac_to_ip {
      
      parseResult=$(egrep -o 'lease.*{|ethernet.*;' /var/lib/dhcp/db/dhcpd.leases | awk '{print $2}' | xargs -n 2 | cut -d ';' -f 1  | grep $1 | awk '{print $1}')
          echo "$parseResult"
      }
      

      我对租约格式了解不多。如果有条目没有“以太网”字段,则上述解析将不起作用。

      【讨论】:

      • 这很像useless use of cat 和相关的反模式。您应该需要零个 cat 实例,除非您专门连接多个输入文件,并且很少超过 grepsed 和 Awk 中的一个,因为列表中的每个实例都有一个包含所有功能的功能集列表中的前一个工具(尽管一些转换,例如换行符确实需要多次调用,所以有时两个甚至三个可能是合理的)。
      【解决方案3】:

      如果您尝试获取 MAC 和 IP,最好使用 arp -s 命令而不是查看 DHCP 租用文件。

      【讨论】:

        【解决方案4】:

        Text::DHCPLeases 也可以完全满足您的需求,而无需重新发明轮子。 :)

        【讨论】:

          【解决方案5】:

          不一定比@ghostdog74好,但这里有一个脚本可以转换成json:

          #!/usr/bin/awk -f
          
          # Start with array creation
          BEGIN {
              printf "[";
          }
          
          # New lease: start object 
          /^lease/ {
              # If that ip is unknown, create a new JSON object
              if (!known[$2]) {
                  # if this object is not the first, print a comma
                  if (!notFirst) {
                      notFirst=1;
                  } else {
                      printf ",";
                  }
          
                  # create a new JSON object with the first key being the IP (column 2)
                  printf "{\"ip\":\"%s\"", $2; known[$2]=1;
          
                  # print subsequent lines, see below
                  p=1;
              }
          }
          
          # If printing is enabled print line as a JSON key/value pair
          p && /^  / {
              # Print key (first word)
              printf ",\"%s\":", $1;
          
              # Clean up the rest of the line: trim whitespace and trailing ;, remove " and escape \
              $1="";
              gsub(/\\/, "\\\\", $0);
              gsub(/"/, "", $0);
              gsub(/^[\t ]*/, "", $0);
              gsub(/;$/, "", $0);
              printf "\"%s\"", $0;
          }
          
          # End of lease: close JSON object and disable printing
          /^\}$/ {
              if (p) {
                  printf "}"
              }
              p=0
          }
          
          # Close the JSON array
          END {
              print "]";
          }
          

          结果:

          $ /opt/dhcpd.leases_to_json.awk /var/lib/dhcp/dhcpd.leases | jq .
          [
            {
              "ip": "10.7.37.10",
              "starts": "3 2019/08/28 22:24:26",
              "ends": "3 2019/08/28 22:34:26",
              "cltt": "3 2019/08/28 22:25:32",
              "binding": "state active",
              "next": "binding state free",
              "rewind": "binding state free",
              "hardware": "ethernet xx:xx:xx:xx:xx:xx",
              "client-hostname": "zzzzzzz"
            },
            {
              "ip": "10.7.37.11",
              "starts": "3 2019/08/28 22:26:10",
              "ends": "3 2019/08/28 22:36:10",
              "cltt": "3 2019/08/28 22:26:10",
              "binding": "state active",
              "next": "binding state free",
              "rewind": "binding state free",
              "hardware": "ethernet xx:xx:xx:xx:xx:xx",
              "uid": "\\001pv\\377\\001\\005~",
              "client-hostname": "xxxx"
            }
          ]
          

          【讨论】:

            猜你喜欢
            • 2020-02-09
            • 1970-01-01
            • 2014-04-28
            • 2012-09-13
            • 2018-10-10
            • 2018-03-31
            • 2018-08-30
            • 2016-10-18
            • 2016-06-15
            相关资源
            最近更新 更多