首页 > 解决方案 > Bash 或 Awk 脚本用于合并 X 个字段匹配的行,同时在不匹配的字段中创建范围

问题描述

需要:我有一个包含如下示例数据的文件。我需要:

  1. 当 X 个字段匹配时,将所有行合并为一行
  2. 当值变化时,在 X 个字段中创建值范围

在这种情况下:将所有行合并到一个字段 $1 到 $6 和 $8 匹配的行中,在字段$7中创建一系列关联值

或者

将所有行合并为一个字段 $1 到 $7匹配的行,在字段$8*中创建一系列关联值

  1. 解决方案必须是 Linux 原生的(如 bash 或 awk 脚本),不需要安装额外的软件(例如 datamash)。

@rtx13 下面使用 TCL 的解决方案确实有效(再次感谢),我只是不确定我是否可以在我的实时环境中安装 TCL,所以我希望和 AWK/BASH/等。也可以提出解决方案。

原始数据:

HOST    FILTER  INTERFACE   SOURCE  DESTINATION PROTOCOL    SOURCE PORT DESTINATION PORT
host1   input   nic1        ip1     ip2         PROT        30000       10
host1   input   nic1        ip1     ip2         PROT        50000       10
host1   input   nic1        ip1     ip2         PROT        60000       10
host1   input   nic1        ip3     ip2         PROT        10          30000
host1   input   nic1        ip3     ip2         PROT        10          50000
host1   input   nic1        ip3     ip2         PROT        10          60000
host1   output  nic1        ip2     ip1         PROT        10          30000
host1   output  nic1        ip2     ip1         PROT        10          50000
host1   output  nic1        ip2     ip1         PROT        10          60000
host1   output  nic1        ip2     ip3         PROT        30000       10
host1   output  nic1        ip2     ip3         PROT        60000       10
host1   output  loc         ip2     ip2         PROT        10          30000
host1   output  loc         ip2     ip2         PROT        10          50000

所需的处理输出:

host1   input   nic1        ip1     ip2         PROT        30000:60000 10
host1   input   nic1        ip3     ip2         PROT        10          30000:60000
host1   output  nic1        ip2     ip1         PROT        10          30000:60000
host1   output  nic1        ip2     ip3         PROT        30000:60000 10
host1   output  loc         ip2     ip2         PROT        10          30000:50000

我是否需要一个单独的文件来列出我想要合并的端口?因为这些也可能在一个范围内?所以脚本可以引用它来知道它是否是一个合并端口?

10|EXAMPLE
22|SSH
80|HTTP
2049|NFS
*etc*

由于我的原始帖子被认为需要更多关注,因此我正在尝试尽可能具体;它收到了一个很接近的答案(谢谢@Enrico Maria De Angelis),但不是一直到那里以及使用datamash的答案(谢谢@oguz ismail),效果很好,但遗憾的是我需要一个不需要的解决方案安装附加软件: 合并除关键字段外所有相同的行,并使关键字段成为范围

标签: linuxbashawkscripting

解决方案


以下内容一次处理一列。


mergecolumn脚本:

#!/usr/bin/tclsh
# check for column number
if { ![llength $argv] || ![regexp {^\d+$} [lindex $argv 0] merge_column] } {
    puts stderr "usage: $argv0 column (0-based)"
    exit 1
}

# read data in and store into 'output' array and 'row_key' list
set rows [lrange [split [read -nonewline stdin] "\n"] 1 end]
foreach row $rows {
    set value [lindex $row $merge_column]
    set row [lreplace $row $merge_column $merge_column "%s"]
    if { ![info exist output($row)] } {
        lappend row_key $row
    }
    lappend output($row) $value
}

# iterate over 'row_key' and generate output
foreach row $row_key {
    if { [llength $output($row)] > 1 } {
        set o [lreplace [lsort -dictionary $output($row)] 1 end-1]
    } else {
        set o $output($row)
    }
    puts [format $row [join $o :]]
}

终端会话:

$ cat data
HOST    FILTER  INTERFACE   SOURCE  DESTINATION PROTOCOL    SOURCE PORT DESTINATION PORT
host1   input   nic1        ip1     ip2         PROT        30000       10
host1   input   nic1        ip1     ip2         PROT        50000       10
host1   input   nic1        ip1     ip2         PROT        60000       10
host1   input   nic1        ip3     ip2         PROT        10          30000
host1   input   nic1        ip3     ip2         PROT        10          50000
host1   input   nic1        ip3     ip2         PROT        10          60000
host1   output  nic1        ip2     ip1         PROT        10          30000
host1   output  nic1        ip2     ip1         PROT        10          50000
host1   output  nic1        ip2     ip1         PROT        10          60000
host1   output  nic1        ip2     ip3         PROT        30000       10
host1   output  nic1        ip2     ip3         PROT        60000       10
host1   output  loc         ip2     ip2         PROT        10          30000
host1   output  loc         ip2     ip2         PROT        10          50000
$ ./mergecolumn 6 < data
host1 input nic1 ip1 ip2 PROT 30000:60000 10
host1 input nic1 ip3 ip2 PROT 10 30000
host1 input nic1 ip3 ip2 PROT 10 50000
host1 input nic1 ip3 ip2 PROT 10 60000
host1 output nic1 ip2 ip1 PROT 10 30000
host1 output nic1 ip2 ip1 PROT 10 50000
host1 output nic1 ip2 ip1 PROT 10 60000
host1 output nic1 ip2 ip3 PROT 30000:60000 10
host1 output loc ip2 ip2 PROT 10 30000
host1 output loc ip2 ip2 PROT 10 50000
$ ./mergecolumn 7 < data
host1 input nic1 ip1 ip2 PROT 30000 10
host1 input nic1 ip1 ip2 PROT 50000 10
host1 input nic1 ip1 ip2 PROT 60000 10
host1 input nic1 ip3 ip2 PROT 10 30000:60000
host1 output nic1 ip2 ip1 PROT 10 30000:60000
host1 output nic1 ip2 ip3 PROT 30000 10
host1 output nic1 ip2 ip3 PROT 60000 10
host1 output loc ip2 ip2 PROT 10 30000:50000
$ 

推荐阅读