根据唯一列合并两个列表文件

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

我有两个文件,一个名为NATLog,有3列,另一个是Sourceports,有2列,下面是NATLog文件的示例。

NATLog

14 172.18.2.12 445 
50 172.18.24.4 123
80 10.2.123.37 22
68 172.18.1.37 25

我想将NATLog文件的最后一列与Sourceports文件的第一列匹配,并将关联的服务作为第4列附加到NATLog文件

Sourceports

445 SMB
123 Network Time Protocol (NTP)
22  SSH
25  SMTP(Insecure)

Desired Output

14 172.18.2.12 445 SMB 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

我正在努力学习AWK来实现这一目标,但我需要一些帮助,请你帮助我,谢谢

linux awk sed
5个回答
1
投票

试试awk,

$ awk ' NR==FNR {x=$1; $1="";a[x]=$0; next } { print $0, a[$3] } ' Sourceports NATLog
14 172.18.2.12 445   SMB
50 172.18.24.4 123  Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

$

3
投票

awk中的另一个(实际上是两个)。这是完美的世界:

$ awk 'NR==FNR{a[$1]=$0;next}{sub($NF,a[$NF])}1' source natlog
14 172.18.2.12 445 SMB 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

解释(并为不完美的世界稍微扩展):

$ awk '
NR==FNR {                          # processing the source file
#   gsub(/&/,"\\\\&")              # if & chars in the file, uncomment to escape them
    a[$1]=$0                       # hash to a, port is the key
    next
}
{                                  # process natlog file
    sub($NF,a[$NF])                # replace port field with entry from source file
#   sub($NF,(a[$NF]?a[$NF]:$NF))   # if gaps in source, use this instead of above
}1' source natlog

一个可能的输出(较短的ip,& char在源和不匹配的端口222):

14 1.18.2.12   445 SMB & 
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 222
68 172.18.1.37 25  SMTP(Insecure)

1
投票
awk '
    NR==FNR { key=$1; sub(/[^[:space:]]+[[:space:]]+/,""); map[key]=$0; next }
    { print $0, map[$3] }
' Sourceports NATLog

1
投票

如果你的目标是以协调方式附加的协议列显示的输出格式,那么printf而不是print提供了man 3 printf中描述的相同的细粒度格式控制(大多数情况下)。在您的情况下,您只需要获取端口号字段的length()并从所需的总字段宽度中减去该值,以便在从NATLog附加保存的协议之前在Sourceports记录之后添加许多空格。

您可以使用类似于以下内容的方法,其中总字段宽度为4用作示例:

$ awk '
    NR==FNR {pcl[$1] = $2; next} {printf "%s%*s%s\n",$0,4-length($3)," ",pcl[$3]}
' Sourceports NATLog

产量

14 172.18.2.12 445 SMB
50 172.18.24.4 123 Network
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

(注意:你的Sourceports在记录的末尾不能包含额外的空格。如果是,那么你将不得不用单独的$0替换$1,$2,$3并相应地调整格式字符串)

通常有很多方法可以在awk中完成同样的事情,因此您可以根据自己的需要量身定制它。

使用pasteawk

较短但效率较低的方法是使用pasteawk来实现同样的目的。 (基本上只输出NATLog的前两个字段,并用Sourceports附加paste的内容,例如

$ paste -d ' ' <(awk '{print $1, $2}' NATLog) Sourceports
14 172.18.2.12 445 SMB
50 172.18.24.4 123 Network Time Protocol (NTP)
80 10.2.123.37 22  SSH
68 172.18.1.37 25  SMTP(Insecure)

(但那真的会打败学习awk的目的)


0
投票

这就是为什么linux有一些小工具,如catcutpaste,在这种情况下join

join -1 3 -2 1 natlog source

加入适用于您尝试使用join的列进行排序的文件。

排序实际上是一个有点错误的措辞。它应该更像是等价的。正如您所注意到的,您的文件具有相同的输入和输出,并且您尝试使用join的列是等效的。所以join将毫无问题地工作。

如果两个文件都没有等效排序,您可以事先使用sort:

join -1 3 -2 1 <(sort -k3 natlog) <(sort source)

或者如果你只想坚持一个程序,那么awk就是前进的方向:

awk '(NR==FNR){k=$3; $3=""; a[k]=$0; next}{ print $0,a[$1] }' natlog source

但如果natlogsource没有相同数量的线和/或键,那么你得到的共同部分是

awk '(NR==FNR){k=$3; $3=""; a[k]=$0; next}($1 in a){ print $0,a[$1] }' natlog source
© www.soinside.com 2019 - 2024. All rights reserved.