sed 或 awk 将两个文件与 sum 组合

Posted

技术标签:

【中文标题】sed 或 awk 将两个文件与 sum 组合【英文标题】:sed or awk combining two files with sum 【发布时间】:2015-08-01 13:25:41 【问题描述】:

我们有脚本可以从 squid access.log 中删除除域名之外的所有内容,并报告每个 URL 的总命中数,我有一个生成的两个文件,一个有缓存命中,另一个有缓存未命中,我正在寻找一种方法来组合这些文件如下 -

cat TCP_MISS_data.txt

Domains    CacheMiss
abc.com    21
def.com    38
xyz.com    12

cat TCP_HITS_data.txt

Domains  CacheHits
def.com  28
abc.com  10
xyz.com

cat Combined_data.txt

Domains    CacheMiss CacheHits  TotalHits
abc.com     21        10          31
def.com     38        28          66
xyz.com     12        0           12

感谢任何帮助。

更新:

我使用下面的 awk 单行从访问日志中删除域和命中,它输出一个包含所有域及其命中的文件,而不管 HITS 和 MISSES。

猫访问.log | awk '打印 $7' | awk '!/^http/sub(/^/,"http://")1' | awk -F"/" '打印 $3' | awk -F":" '打印 $1' | awk -F"。" 'f1=NF;f2=NF-1;打印 $f2 "." $f1' |排序 |唯一的-c |排序 -n

为了区分我在下面所做的命中和未命中 -

猫访问.log | grep TCP_MISS | awk '打印 $7' | awk '!/^http/sub(/^/,"http://")1' | awk -F"/" '打印 $3' | awk -F":" '打印 $1' | awk -F"。" 'f1=NF;f2=NF-1;打印 $f2 "." $f1' |排序 |唯一的-c |排序 -n > TCP_MISS_data 猫访问.log | grep TCP_HIT | awk '打印 $7' | awk '!/^http/sub(/^/,"http://")1' | awk -F"/" '打印 $3' | awk -F":" '打印 $1' | awk -F"。" 'f1=NF;f2=NF-1;打印 $f2 "." $f1' |排序 |唯一的-c |排序 -n > TCP_HITS_data

现在我得到了两个文件,TCP_MISS_data 和 TCP_HITS_data,它们的行不相等,我尝试按照我上面的帖子中的说明合并这两个文件。

【问题讨论】:

你被困在哪里了? Tom 我仍然是 awk 的新手,但我会尝试完成 Kent 的一个班轮。谢谢。 新手并没有错,您只需要在您的问题中表现出一些研究成果。如果您自己尝试过某些东西但它不起作用,请edit 您的问题向我们展示。否则不清楚你的问题到底出在哪里,看起来你只是想让别人为你写一些代码。 【参考方案1】:

这个oneliner可以完成这项工作:

 awk 'NR==FNRa[$1]=$2;next
     $1 in aprintf "%s %s %s %s\n", $1,a[$1],($2?$2:0),(FNR>1?a[$1]+$2:"TotalHits")' missFile hitFile

要获得“漂亮”的输出格式,您可以调整printf 格式,或者像awk ..... |column -t 一样将结果通过管道传输到column -t

使用您的示例输入:

kent$  head f*
==> f1 <==
Domains    CacheMiss
abc.com    21
def.com    38
xyz.com    12

==> f2 <==
Domains  CacheHits
def.com  28
abc.com  10
xyz.com

kent$  awk 'NR==FNRa[$1]=$2;next$1 in aprintf "%s %s %s %s\n", $1,a[$1],($2?$2:0),(FNR>1?a[$1]+$2:"TotalHits")' f1 f2|column -t
Domains  CacheMiss  CacheHits  TotalHits
def.com  38         28         66
abc.com  21         10         31
xyz.com  12         0          12

编辑:

添加一些解释:

awk 'NR==FNRa[$1]=$2;next           #process the first file, store in a hashtable, key:col1, value:col2
$1 in a                               #starting processing 2nd file, if file2.col1 in hashtable, do followings:
printf "%s %s %s %s\n", $1,a[$1],    #printf output with format
($2?$2:0),                            #if file2.cols was empty, we take it as 0
(FNR>1?a[$1]+$2:"TotalHits")          #if first line, we dont do sum, print "totalHits" text
' f1 f2                              #two input files

【讨论】:

解释一下你的脚本会很有用,希望下次OP遇到任何问题时,他们的第一个想法是让其他人在这里为他们解决。 @TomFenech 好的,我添加了一些描述,尽管我认为代码足够简单。 感谢 Kent 的回复,您提供的脚本仅适用于 5 行,即如果 f2 有 5 行而 f1 有 100 行,则其匹配值仅适用于 f1 中的 5 个域。我需要获取 f1 中所有 100 行的命中和未命中,如果域不存在 f1,它可以在 TotalHits 中显示 0 吗?再次感谢。 您应该在问题中提出这些要求。尝试DIY一下,我已经完成了:“if some key in hashtable”的部分,你可以试试else部分。

以上是关于sed 或 awk 将两个文件与 sum 组合的主要内容,如果未能解决你的问题,请参考以下文章

shell中 sed或awk 把文件的两个字段调换位置

AWK&SED

如何在两个模式之间打印线,包括或不包括(在 sed、AWK 或 Perl 中)?

如何在两个模式之间打印线,包括或不包括(在 sed、AWK 或 Perl 中)?

如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?

如何选择可能使用 awk/sed 多次出现的两个标记模式之间的行