Bash + awk 高级解析

问题描述 投票:0回答:1

我想使用 awk 和一些逻辑创建一个 oneliner。这是要使用的命令和输出:

grep -v "local_address" --no-filename "/proc/net/tcp" "/proc/net/tcp6"
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7714 1 000000009796c30c 100 0 0 10 0
   1: 845DA8C0:1F91 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 66072 1 0000000080e84053 100 0 0 10 0
   2: 0100007F:86FD 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 476 1 000000005f80511b 100 0 0 10 0
   3: 00000000:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 29391 1 0000000098b1d0d1 100 0 0 10 0
   4: 00000000:1F92 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 66342 1 0000000004ea4afe 100 0 0 10 0
   5: 9F01A8C0:0016 0101A8C0:E488 01 00000000:00000000 02:000AD0D3 00000000     0        0 68121 2 000000008fdfa15d 20 4 16 10 -1
   0: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7716 1 0000000037928e79 100 0 0 10 0

我正在创建一个函数来检测可能的端口冲突,并且我已经有了用于将 ip 和端口从十六进制转换为十进制的函数,反之亦然。例如,在本例中,IP 192.168.93.132 是 845DA8C0。因此,如果我询问此接口上可能存在的端口冲突,则查询应返回与此 ip (845DA8C0) 相关的所有端口以及与十进制 0.0.0.0 上的 00000000 相关的所有端口,并且也会影响和冲突。因此,在这种情况下,正确答案应该是 0016、1F91、1F90 和 1F92(不相关,但在 12 月中是端口 22、8081、8080 和 8082)。我还想要包含 0A 或任何值的 $4 列,因为它用于确定端口是否被使用。所以预期和期望的输出应该是:

00160A
1F910A
1F900A
1F920A

我当前的 oneliner 方法是将所有端口添加到阵列中,无论它们位于什么接口上:

declare -a busy_ports=($(grep -v "local_address" --no-filename "/proc/net/tcp" "/proc/net/tcp6" | awk '{print $2$4}' | cut -d ":" -f 2 | sort -u))

因此,如果执行此错误或不完整的方法,这就是输出:

001601
00160A
1F900A
1F910A
1F920A
86FD0A

我想在 awk 级别添加一层逻辑,仅当该行具有给定的 IP 地址(在本例中为 845DA8C0 或 00000000)时才进行匹配。有人可以帮忙吗?

bash parsing awk text-parsing
1个回答
0
投票

模拟 OP 的

grep -v
输出:

$ cat grep.out
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7714 1 000000009796c30c 100 0 0 10 0
   1: 845DA8C0:1F91 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 66072 1 0000000080e84053 100 0 0 10 0
   2: 0100007F:86FD 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 476 1 000000005f80511b 100 0 0 10 0
   3: 00000000:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 29391 1 0000000098b1d0d1 100 0 0 10 0
   4: 00000000:1F92 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 66342 1 0000000004ea4afe 100 0 0 10 0
   5: 9F01A8C0:0016 0101A8C0:E488 01 00000000:00000000 02:000AD0D3 00000000     0        0 68121 2 000000008fdfa15d 20 4 16 10 -1
   0: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7716 1 0000000037928e79 100 0 0 10 0

一个

awk
方法:

cat grep.out | awk -v iplist='845DA8C0,00000000' '    # set awk variable "iplist" to set of ip addresses delimited by comma

BEGIN { split(iplist,a,",")                           # split iplist into array a[]
        for (i in a) ips[a[i]]                        # convert a[1]=845DA8C0 to ips[845DA8C0]
      }
      { split($2,a,":")                               # split 2nd field on ":"
        if (a[1] in ips)                              # if 1st tuple is an index in ips[] array then ...
           ports[a[2] $4]                             # save 2nd tuple and 4th field as index in array ports[]; this will eliminate duplicates
      }
END   { for (port in ports)                           # loop through indices of port[] array and ...
            print port                                # print the port info to stdout
      }
' | sort                                              # output order from this awk script is not guaranteed to let "sort" provide the desired order

这会生成:

00160A
1F910A
1F900A
1F920A

正如评论中所指出的,一旦将

awk
融入其中,通常就可以消除对
grep
cut
和使用
sort
(过滤掉重复项)的需要。

修改

awk
脚本以直接处理
/proc/net
文件:

awk -v iplist='845DA8C0,00000000' '

BEGIN           { split(iplist,a,",")
                  for (i in a) ips[a[i]]
                }

/local_address/ { next }                         # skip processing lines that contain the string "local_address"

                { split($2,a,":")
                  if (a[1] in ips)
                     ports[a[2] $4]
                }
END             { for (port in ports)
                      print port
                }
' /proc/net/tcp /proc/net/tcp6 | sort

删除注释并使其更难阅读(即变成一行行):

awk -v iplist='845DA8C0,00000000' ' BEGIN { split(iplist,a,",") for (i in a) ips[a[i]] } /local_address/ { next } { split($2,a,":") if (a[1] in ips) ports[a[2] $4] } END { for (port in ports) print port } ' /proc/net/tcp /proc/net/tcp6
© www.soinside.com 2019 - 2024. All rights reserved.