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

awk - Find duplicate records in multiple files

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

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

我尝试了几种方法,但 none 对我有用。

是这样的吗?

 awk '{id=; k= FS ; 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

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

假设预期输出的最后一行应该包括 f1/5,那么下面的代码比其他答案稍微不那么曲折,但它更冗长——但没有处理任何文件两次。但是,编码很痛苦。有一个逻辑行号,它是具有 4 个字段的行的前导 1.(具有 3 个字段的行不算逻辑行)以及文件中的物理行号(FNR) .

script.awk

FILENAME != ofn { ofn = FILENAME; log_line_num = 0 }
FNR == NR {
            line[FNR] = [=10=]
            len = length([=10=])
            if (len > maxlen)
                maxlen = len
            if (NF == 4)
            {
                name = 
                names[name]++
                name_on_line[FNR] = name
            }
            numlines++
          }
NF == 4   { name = 
            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]
            }
          }

解释:

  • 记录当前文件名,当文件名改变时重新设置逻辑行号。
  • 对于第一个文件中的行:
    • 记录行数组中由物理行号(FNR — 文件记录号)索引的行。
    • 追踪最长的输入行
    • 如果字段数为4,则记录名称存在,并且出现在物理行号上
  • 对于具有 4 个字段的行(在所有文件中),它:
    • 增加逻辑行号
    • 如果名称是第一个文件中的一个,则检查该名称是否已在当前文件中看到(names_in_file)
    • 如果不是,则在 data[name] 非空的情况下添加下划线,并将文件名、斜线和逻辑行号添加到 data[name]
    • else 添加一个逗号和逻辑行号到 data[name]
  • 最后
    • 创建一个方便的格式字符串,将文件信息放在文件 1 中最长行之后的 3 个空格
    • 对于文件 1 中的每个物理行号
    • 如果该行有 4 个字段(name_on_line[i] 已定义),则打印保存的行以及来自 data 数组
    • 的行名称的行号
    • 否则只打印保存的(3 个字段)行

示例输出

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

替代示例输出:

$ awk -f script.awk file.[123]
1. c2 888888  somestuff   file.1/1,5_file.2/5_file.3/6
2. c2 999999  somestuff   file.1/2_file.2/2_file.3/2
   c2 999999  somestuff
3. c2 777777  somestuff   file.1/3_file.2/4_file.3/4
4. c2 666666  somestuff   file.1/4_file.3/5
5. c2 888888  somestuff   file.1/1,5_file.2/5_file.3/6
$