awk - 在多个文件中查找重复记录

时间:2016-08-17 19:05:21

标签: file awk compare text-processing

我想在一个文件(f1)的第三列中找到包含多个文件(f2,f3,... fn)的重复记录,并在格式为每行(在新列中)打印结果:Filename / FirstColumn < / p>

f1
1. 11:10 *Jane> login
2. 11:15 *Bob>  login
   11:16 *Bob>  logout
3. 11:45 *Jane> login
4. 01:20 *John>  login
5. 02:30 *Deborah  logout

f2
1. 12:10 *Jane> login
2. 13:00 *Dorothy  logout
3. 13:15 *Bob>  login
   14:16 *Bob>  logout
4. 15:45 *Jane> login
5. 06:20 *John>  login

f3
1. 15:10 *Jane> login
2. 15:50 *Mark> login
3. 16:10 *Dorothy  logout
4. 17:18 *Bob>  login
   18:16 *Bob>  logout
5. 19:45 *Jane> login
6. 20:21 *John>  login

输出到f1-dup

f1-dup
1. 11:10 *Jane> login    f1/1,3_f2/1,4_f3/1,5
2. 11:15 *Bob>  login    f1/2_f2/3_f3/4
   11:16 *Bob>  logout
3. 11:45 *Jane> login    f1/1,3_f2/1,4_f3/1,5
4. 01:20 *John>  login   f1/4_f2/5_f3/6
5. 02:30 *Deborah  logout

我尝试了几种方法,但它们都不适用于我。

2 个答案:

答案 0 :(得分:2)

这样的事情?

 awk '{id=$1; k=$3 FS $4; pid=sub(/\./,"",id)} 
     NR==FNR{if(pid) a[k]=(a[k]?a[k]",":"\t"FILENAME"/")id
             keyfile=FILENAME; next}
     FILENAME==keyfile{$(NF+1)=a[k];print;next}
     k in a && pid{a[k]=a[k] (fx[k]!=FILENAME?"_"FILENAME"/":",") id;
                              fx[k]=FILENAME}' f1 f2 f3 f1

1. 11:10 *Jane> login   f1/1,3_f2/1,4_f3/1,5
2. 11:15 *Bob> login    f1/2_f2/3_f3/4
11:16 *Bob> logout
3. 11:45 *Jane> login   f1/1,3_f2/1,4_f3/1,5
4. 01:20 *John> login   f1/4_f2/5_f3/6
5. 02:30 *Deborah logout        f1/5

我认为可以进一步简化,也可以修复未编号记录的格式。

答案 1 :(得分:1)

假设预期输出的最后一行应该包含f1/5,那么下面的代码比另一个代码稍微不那么狡猾,但是它更加冗长 - 但是没有处理任何文件两次。但编码很痛苦。有一个逻辑行号,它是一行上的前导1.,有4个字段(3个字段的行并不算作逻辑行)以及文件中的物理行号({ {1}})。

FNR

script.awk

说明:

  • 保留当前文件名的记录,并在名称更改时重置逻辑行号。
  • 对于第一个文件中的行:
    • 记录由物理行号(FNR - 文件记录号)索引的行数组中的行。
    • 跟踪最长的输入行
    • 如果字段数为4,则记录该名称存在,并显示在物理行号上
  • 对于包含4个字段的行(在所有文件中),它:
    • 增加逻辑行号
    • 如果名称是第一个文件中的名称之一,则检查当前文件中是否已显示该名称(FILENAME != ofn { ofn = FILENAME; log_line_num = 0 } FNR == NR { line[FNR] = $0 len = length($0) if (len > maxlen) maxlen = len if (NF == 4) { name = $3 names[name]++ name_on_line[FNR] = name } numlines++ } NF == 4 { name = $3 log_line_num++ if (name in names) { if (name_in_file[FILENAME,name]++ == 0) { us = (data[name] != "") ? "_" : "" extra = us FILENAME "/" log_line_num } else extra = "," log_line_num data[name] = data[name] extra } } END { fmt = "%-" maxlen "s %s\n" for (i = 1; i <= numlines; i++) { if (i in name_on_line) printf(fmt, line[i], data[name_on_line[i]]) else print line[i] } }
    • 如果没有,则在names_in_file添加下划线(如果非空)并将文件名,斜杠和逻辑行号添加到data[name]
    • 否则将逗号和逻辑行号添加到data[name]
  • 最后
    • 创建一个方便的格式字符串,将文件信息放在文件1中最长行之后的3个空格
    • 表示文件1中的每个物理行号
    • 如果该行有4个字段(已定义data[name]),则打印保存的行以及name_on_line[i]数组
    • 行中名称的行号
    • 其他只需打印已保存的(3字段)行

示例输出

data

替代数据文件

1. 11:10 *Jane> login f1/1,3_f2/1,4_f3/1,5 2. 11:15 *Bob> login f1/2_f2/3_f3/4 11:16 *Bob> logout 3. 11:45 *Jane> login f1/1,3_f2/1,4_f3/1,5 4. 01:20 *John> login f1/4_f2/5_f3/6 5. 02:30 *Deborah logout f1/5

file.1

1. c2 888888 somestuff 2. c2 999999 somestuff c2 999999 somestuff 3. c2 777777 somestuff 4. c2 666666 somestuff 5. c2 888888 somestuff

file.2

1. c2 333333 somestuff 2. c2 999999 somestuff 3. c2 444444 somestuff 4. c2 777777 somestuff 5. c2 888888 somestuff 6. c2 555555 somestuff

file.3

替代样本输出:

1. c2 333333  somestuff
2. c2 999999  somestuff
3. c2 444444  somestuff
4. c2 777777  somestuff
5. c2 666666  somestuff
6. c2 888888  somestuff
7. c3 222222  somestuff