Linux Bash或Awk脚本合并X个字段匹配的行,同时在不';不匹配
需要:我有一个包含以下示例数据的文件。我需要:Linux Bash或Awk脚本合并X个字段匹配的行,同时在不';不匹配,linux,bash,awk,scripting,Linux,Bash,Awk,Scripting,需要:我有一个包含以下示例数据的文件。我需要: 当X个字段数匹配时,将所有行合并为一行 当值发生变化时,在X个字段中创建值范围 在这种情况下: 将所有行合并到一个字段$1到$6和$8匹配的行中,在字段中创建一系列相关值$7 或 将所有行合并到一个匹配的字段$1到$7中,在字段$8*中创建一个关联值范围 解决方案必须是Linux本机的(如bash或awk脚本),不需要安装其他软件(如datamash) @下面使用TCL的rtx13解决方案确实有效(再次感谢),我只是不确定是否可以在我的实时环境中安
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
所需的处理输出:
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),效果很好,但遗憾的是,我需要一个不需要安装附加软件的解决方案:
以下内容一次只能在一列上工作
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 :]]
}
#!/usr/bin/tclsh
# 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 {
if { [lsearch -exact $argv [lindex $row 6]] >= 0 } {
set merge_column 7
} elseif { [lsearch -exact $argv [lindex $row 7]] >= 0 } {
set merge_column 6
} else {
set merge_column -1 ;# do not merge
}
if { $merge_column >= 0 } {
set value [lindex $row $merge_column]
set row [lreplace $row $merge_column $merge_column "%s"]
} else {
set value ""
set row [list {*}$row] ;# trim spaces for consistency
}
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数据
主机筛选器接口源目标协议源端口目标端口
主机1输入nic1 ip1 ip2保护30000 10
主机1输入nic1 ip1 ip2保护50000 10
主机1输入nic1 ip1 ip2保护60000 10
主机1输入nic1 ip3 ip2保护10 30000
主机1输入nic1 ip3 ip2保护10 50000
主机1输入nic1 ip3 ip2保护10 60000
主机1输出nic1 ip2 ip1保护10 30000
主机1输出nic1 ip2 ip1保护10 50000
主机1输出nic1 ip2 ip1保护10 60000
主机1输出nic1 ip2 ip3保护30000 10
主机1输出nic1 ip2 ip3保护60000 10
主机1输出位置ip2 ip2保护10 30000
主机1输出位置ip2 ip2保护10 50000
美元/合并第6列<数据
主机1输入nic1 ip1 ip2保护30000:60000 10
主机1输入nic1 ip3 ip2保护10 30000
主机1输入nic1 ip3 ip2保护10 50000
主机1输入nic1 ip3 ip2保护10 60000
主机1输出nic1 ip2 ip1保护10 30000
主机1输出nic1 ip2 ip1保护10 50000
主机1输出nic1 ip2 ip1保护10 60000
主机1输出nic1 ip2 ip3保护30000:60000 10
主机1输出位置ip2 ip2保护10 30000
主机1输出位置ip2 ip2保护10 50000
美元/合并第7列<数据
主机1输入nic1 ip1 ip2保护30000 10
主机1输入nic1 ip1 ip2保护50000 10
主机1输入nic1 ip1 ip2保护60000 10
主机1输入nic1 ip3 ip2保护10 30000:60000
主机1输出nic1 ip2 ip1保护10 30000:60000
主机1输出nic1 ip2 ip3保护30000 10
主机1输出nic1 ip2 ip3保护60000 10
主机1输出位置ip2 ip2保护10 30000:50000
$
以下内容适用于两列。通过命令行提供要合并的端口列表
mergecolumn2
脚本:
#!/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 :]]
}
#!/usr/bin/tclsh
# 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 {
if { [lsearch -exact $argv [lindex $row 6]] >= 0 } {
set merge_column 7
} elseif { [lsearch -exact $argv [lindex $row 7]] >= 0 } {
set merge_column 6
} else {
set merge_column -1 ;# do not merge
}
if { $merge_column >= 0 } {
set value [lindex $row $merge_column]
set row [lreplace $row $merge_column $merge_column "%s"]
} else {
set value ""
set row [list {*}$row] ;# trim spaces for consistency
}
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 :]]
}
终端会话:
$。/mergecolumn2
您能否澄清合并要求?看起来您还需要将所有行合并为一个字段$1到$6和$7匹配的行,在字段$8中创建一个关联值范围…@rtx13 Argh,抱歉,这是我第一次尝试发布内容!没错,有两种情况需要合并。我已经用第二种方案更新了我的帖子。@rtx13您的评论也让我认为我需要一个单独的文件,其中列出了我要合并的特定端口?没问题,只是想了解问题的范围。您是否碰巧在需要运行此代码的系统上提供了tcl
?您可以从shell/终端运行tclsh
进行检查。@rtx13它当前没有安装tcl,但是它看起来像是直接从Redhat获得的,所以我可以从本地repo中提取它。OP对tcl没有问题。请参阅问题下方的评论和聊天。非常感谢tcl脚本。我仍然不确定是否可以在我的环境中安装tcl,但在测试系统上使用它非常有吸引力。干得好@juggy_gales很乐意帮忙。如果此答案或任何其他答案解决了您的问题,请将其标记为已接受。要接受答案,请单击复选标记按钮(✓) 恩德内亚