从 'iptables -nvL' 命令输出中有选择地删除不必要的列空格?

Selectively remove unnecessary column whitespace from 'iptables -nvL' command output?

目标

我们正在寻求更改此输出(从 运行 下面的基于 iptables(8) 的脚本生成,在 Ubuntu 18.04 上解析 original, raw, anonymized iptables -nvL output from one of our servers):

Chain INPUT (policy DROP 2525 packets, 130K bytes)
target                      prot        opt      in           out   source          destination
ufw-before-logging-input    all         --       *            *     0.0.0.0/0       0.0.0.0/0
ufw-before-input            all         --       *            *     0.0.0.0/0       0.0.0.0/0
ufw-after-input             all         --       *            *     0.0.0.0/0       0.0.0.0/0
ufw-after-logging-input     all         --       *            *     0.0.0.0/0       0.0.0.0/0
ufw-reject-input            all         --       *            *     0.0.0.0/0       0.0.0.0/0
ufw-track-input             all         --       *            *     0.0.0.0/0       0.0.0.0/0

...更窄,列之间不必要的空格更少:

Chain INPUT (policy DROP 2525 packets, 130K bytes)
target                      prot   opt   in   out   source          destination
ufw-before-logging-input    all    --    *    *     0.0.0.0/0       0.0.0.0/0
ufw-before-input            all    --    *    *     0.0.0.0/0       0.0.0.0/0
ufw-after-input             all    --    *    *     0.0.0.0/0       0.0.0.0/0
ufw-after-logging-input     all    --    *    *     0.0.0.0/0       0.0.0.0/0
ufw-reject-input            all    --    *    *     0.0.0.0/0       0.0.0.0/0
ufw-track-input             all    --    *    *     0.0.0.0/0       0.0.0.0/0

我们更喜欢 bash 脚本,我们可以更轻松地(比 下面的脚本)随着时间的推移调整每个列间距的宽度 on 每列基础。我们还不能让基于 awk 的东西像 sprintf, gsub, or this mechanism 做我们想做的事。

bash 解决方案可以完成 similar/same 事情也可能有效。

更具挑战性的输入

iptables -nvL output这部分(下面的脚本未解析)比较难,因为最右边的自由格式列,内容中唯一有空格的列:

Chain ufw-after-input (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    1    78 ufw-skip-to-policy-input  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:137
    0     0 ufw-skip-to-policy-input  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:138
    0     0 ufw-skip-to-policy-input  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:139
    5   260 ufw-skip-to-policy-input  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:445
    0     0 ufw-skip-to-policy-input  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
    0     0 ufw-skip-to-policy-input  udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:68
    0     0 ufw-skip-to-policy-input  all  --  *      *       xxx.xxx.xxx.xxx/yy   xxx.xxx.xxx.xxx/yy   ADDRTYPE match dst-type BROADCAST

Chain ufw-after-logging-forward (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 LOG        all  --  *      *       xxx.xxx.xxx.xxx/yy   xxx.xxx.xxx.xxx/yy   limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "

上面的一个很好的转换看起来像这样:

Chain ufw-after-input (1 references)
target                    prot opt in  out  source              destination
ufw-skip-to-policy-input  udp  --  *   *    0.0.0.0/0           0.0.0.0/0           udp dpt:137
ufw-skip-to-policy-input  udp  --  *   *    0.0.0.0/0           0.0.0.0/0           udp dpt:138
ufw-skip-to-policy-input  tcp  --  *   *    0.0.0.0/0           0.0.0.0/0           tcp dpt:139
ufw-skip-to-policy-input  tcp  --  *   *    0.0.0.0/0           0.0.0.0/0           tcp dpt:445
ufw-skip-to-policy-input  udp  --  *   *    0.0.0.0/0           0.0.0.0/0           udp dpt:67
ufw-skip-to-policy-input  udp  --  *   *    0.0.0.0/0           0.0.0.0/0           udp dpt:68
ufw-skip-to-policy-input  all  --  *   *    xxx.xxx.xxx.xxx/yy  xxx.xxx.xxx.xxx/yy  ADDRTYPE match dst-type BROADCAST

Chain ufw-after-logging-forward (1 references)
target                    prot opt in  out  source              destination         
LOG                       all  --  *   *    xxx.xxx.xxx.xxx/yy  xxx.xxx.xxx.xxx/yy  limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "

原版iptablesbash剧本

生成上面输出的第一个版本的脚本;这可以说是一个不优雅的 hack:

#!/usr/bin/env bash
#
# Pretty-print 'iptables -nvL' output.
# 1. remove the 'pkts' and 'bytes' columns
# 2. make column-aligned, table-based output per
#    https://gist.github.com/Airdawg5571/1a8c49ca5dd97af55ab9
# 3. attempt to make narrower, removing unnecessary whitespace
#    between columns, to save previous display-screen realestate
#
iptables -nvL                                                      | \
    # remove the 'pkts' and 'bytes' columns
    awk '{ if ( != "Chain") { =""; =""; print } else print}' | \
    # make tabular (table) output
    column -t                                                      | \
    sed 's/^Chain/\n&/g'                                           | \
    sed '/^Chain/ s/[ \t]\{1,\}/ /g'                               | \
    sed '/^[0-9]/ s/[ \t]\{1,\}/ /10g'                             | \
    # reduce the unnecessary whitespace after 'prot' column
    perl -pe 's|^(?!Chain)([^\s]+\s+\w+)\s+|  \t|'               | \
    # arbitrarily truncate line length
    cut -c -120

使用Steve Kinzler's align util

align -e '!/^Chain/' -g 4 < file.txt

输出,(-e防止首行对齐,-g设置最小gutter为4个空格:

Chain INPUT (policy DROP 2525 packets, 130K bytes)
target                      prot    opt    in    out    source       destination
ufw-before-logging-input    all     --     *     *      0.0.0.0/0    0.0.0.0/0
ufw-before-input            all     --     *     *      0.0.0.0/0    0.0.0.0/0
ufw-after-input             all     --     *     *      0.0.0.0/0    0.0.0.0/0
ufw-after-logging-input     all     --     *     *      0.0.0.0/0    0.0.0.0/0
ufw-reject-input            all     --     *     *      0.0.0.0/0    0.0.0.0/0
ufw-track-input             all     --     *     *      0.0.0.0/0    0.0.0.0/0

Per-column formatting: -a开关控制格式样式,但不能设置单独的列宽.示例 -- r右对齐第一列,对接下来的四列使用 d默认对齐,然后 r右对齐其余列:

align -e '!/^Chain/' -a r4dr < file.txt 

输出:

Chain INPUT (policy DROP 2525 packets, 130K bytes)
                  target prot opt in out    source destination
ufw-before-logging-input all  --  *  *   0.0.0.0/0   0.0.0.0/0
        ufw-before-input all  --  *  *   0.0.0.0/0   0.0.0.0/0
         ufw-after-input all  --  *  *   0.0.0.0/0   0.0.0.0/0
 ufw-after-logging-input all  --  *  *   0.0.0.0/0   0.0.0.0/0
        ufw-reject-input all  --  *  *   0.0.0.0/0   0.0.0.0/0
         ufw-track-input all  --  *  *   0.0.0.0/0   0.0.0.0/0

鉴于您更新的问题和评论(并使用 cat file 代替 iptables -nvL 我的系统上没有)::

$ cat tst.awk
BEGIN { nf = split("0 0 27 7 6 5 5 20 20",w) }
NF && !/^Chain/ {
    for (i=3; i<=nf; i++) {
        printf "%-*s", w[i], $i
    }
    sub("^([[:space:]]*[^[:space:]]+){"nf"}[[:space:]]*","")
}
{ print }

.

$ cat file | awk -f tst.awk
Chain ufw-after-input (1 references)
target                     prot   opt   in   out  source              destination
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:137
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:138
ufw-skip-to-policy-input   tcp    --    *    *    0.0.0.0/0           0.0.0.0/0           tcp dpt:139
ufw-skip-to-policy-input   tcp    --    *    *    0.0.0.0/0           0.0.0.0/0           tcp dpt:445
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:67
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:68
ufw-skip-to-policy-input   all    --    *    *    xxx.xxx.xxx.xxx/yy  xxx.xxx.xxx.xxx/yy  ADDRTYPE match dst-type BROADCAST

Chain ufw-after-logging-forward (1 references)
target                     prot   opt   in   out  source              destination
LOG                        all    --    *    *    xxx.xxx.xxx.xxx/yy  xxx.xxx.xxx.xxx/yy  limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "

当 运行 针对 https://gist.githubusercontent.com/johnnyutahh/fdccf18b2c6529e17252cfca9703185e/raw 提供的示例输入时,我得到以下结果,我没有看到任何问题,所以如果你说这个输出不正确,你d 必须指出问题出在哪里:

$ awk -f tst.awk file
Chain INPUT (policy DROP 35 packets, 1771 bytes)
target                     prot   opt   in   out  source              destination
ufw-before-logging-input   all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-before-input           all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-input            all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-logging-input    all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-reject-input           all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-track-input            all    --    *    *    0.0.0.0/0           0.0.0.0/0

Chain FORWARD (policy DROP 0 packets, 0 bytes)
target                     prot   opt   in   out  source              destination
ufw-before-logging-forward all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-before-forward         all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-forward          all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-logging-forward  all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-reject-forward         all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-track-forward          all    --    *    *    0.0.0.0/0           0.0.0.0/0

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
target                     prot   opt   in   out  source              destination
ufw-before-logging-output  all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-before-output          all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-output           all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-after-logging-output   all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-reject-output          all    --    *    *    0.0.0.0/0           0.0.0.0/0
ufw-track-output           all    --    *    *    0.0.0.0/0           0.0.0.0/0

Chain ufw-after-forward (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-after-input (1 references)
target                     prot   opt   in   out  source              destination
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:137
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:138
ufw-skip-to-policy-input   tcp    --    *    *    0.0.0.0/0           0.0.0.0/0           tcp dpt:139
ufw-skip-to-policy-input   tcp    --    *    *    0.0.0.0/0           0.0.0.0/0           tcp dpt:445
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:67
ufw-skip-to-policy-input   udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp dpt:68
ufw-skip-to-policy-input   all    --    *    *    0.0.0.0/0           0.0.0.0/0           ADDRTYPE match dst-type BROADCAST

Chain ufw-after-logging-forward (1 references)
target                     prot   opt   in   out  source              destination
LOG                        all    --    *    *    0.0.0.0/0           0.0.0.0/0           limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "

Chain ufw-after-logging-input (1 references)
target                     prot   opt   in   out  source              destination
LOG                        all    --    *    *    0.0.0.0/0           0.0.0.0/0           limit: avg 3/min burst 10 LOG flags 0 level 4 prefix "[UFW BLOCK] "

Chain ufw-after-logging-output (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-after-output (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-before-forward (1 references)
target                     prot   opt   in   out  source              destination
ACCEPT                     all    --    *    *    0.0.0.0/0           0.0.0.0/0           ctstate RELATED,ESTABLISHED
ACCEPT                     all    --    wg0  *    0.0.0.0/0           0.0.0.0/0
ACCEPT                     icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 3
ACCEPT                     icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 11
ACCEPT                     icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 12
ACCEPT                     icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 8
ufw-user-forward           all    --    *    *    0.0.0.0/0           0.0.0.0/0

Chain ufw-before-input (1 references)
target                     prot   opt   in   out  source              destination
ACCEPT                     all    --    lo   *    0.0.0.0/0           0.0.0.0/0
ACCEPT                     all    --    *    *    0.0.0.0/0           0.0.0.0/0           ctstate RELATED,ESTABLISHED
ufw-logging-deny           all    --    *    *    0.0.0.0/0           0.0.0.0/0           ctstate INVALID
DROP                       all    --    *    *    0.0.0.0/0           0.0.0.0/0           ctstate INVALID
ACCEPT                     icmp   --    *    *    xxx.xxx.xxx.xxx/yy  0.0.0.0/0           icmptype 8
ACCEPT                     icmp   --    *    *    xxx.xxx.xxx.xxx/yy  0.0.0.0/0           icmptype 8
ACCEPT                     icmp   --    *    *    xxx.xxx.xxx.xxx/yy  0.0.0.0/0           icmptype 8
DROP                       icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 3
DROP                       icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 11
DROP                       icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 12
DROP                       icmp   --    *    *    0.0.0.0/0           0.0.0.0/0           icmptype 8
DROP                       udp    --    *    *    0.0.0.0/0           0.0.0.0/0           udp spt:67 dpt:68
ufw-not-local              all    --    *    *    0.0.0.0/0           0.0.0.0/0
DROP                       udp    --    *    *    0.0.0.0/0           224.0.0.251         udp dpt:5353
DROP                       udp    --    *    *    0.0.0.0/0           239.255.255.250     udp dpt:1900
ufw-user-input             all    --    *    *    0.0.0.0/0           0.0.0.0/0

Chain ufw-before-logging-forward (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-before-logging-input (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-before-logging-output (1 references)
target                     prot   opt   in   out  source              destination

Chain ufw-before-output (1 references)
target                     prot   opt   in   out  source              destination
ACCEPT                     all    --    *    lo   0.0.0.0/0           0.0.0.0/0
ACCEPT                     all    --    *    *    0.0.0.0/0           0.0.0.0/0           ctstate RELATED,ESTABLISHED

这个有效:

#!/usr/bin/env bash

#
# Pretty-print iptables(8) output.
#
# source:
# https://gitlab.com/johnnyutahh/swmisc/-/blob/master/sysadmin/networking/iptables/iptables-list-pretty.sh
#
# (The following script was Ubuntu-18.04 tested on 2020-05-17.)
#

# Derivered from
# https://www.reddit.com/r/bash/comments/gl61yb/selectively_remove_unnecessary_column_whitespace/fqw19tv

# Adjust these values to resize column widths
column_widths=(0 0 27 5 4 8 8 17 17)

iptables_align()
{
  while read line; do
    if [[ $line =~ Chain ]]; then
      echo "$line"
    else
      line=${line//\*/\\*}
      array=($line)
      for n in {2..8}; do
        w=${column_widths[$n]}
         printf "%-${w}s" "${array[$n]}"
      done
      lastcol_with_spaces_in_content=("${array[@]:9}")
      printf "%s" "${lastcol_with_spaces_in_content[*]}"
      echo
    fi
  done
}

iptables -nvL | iptables_align | sed -s 's|\\*|* |g' | less

来源:

https://gitlab.com/johnnyutahh/swmisc/-/blob/master/sysadmin/networking/iptables/iptables-list-pretty.sh