【问题标题】:awk - Find duplicate records in multiple filesawk - 在多个文件中查找重复记录
【发布时间】:2016-12-24 13:42:35
【问题描述】:

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

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

我尝试了几种方法,但没有一个适合我。

【问题讨论】:

  • 行首有时出现有时不出现的数字是什么?它们是数据文件的一部分,还是您的演示文稿的一部分?数字不存在有什么意义?第三列是哪个?出现这种情况的部分原因是数字不稳定——您是否只查看登录和注销的值?你似乎也关心这些​​名字。 “Jane Login”的条目之间似乎也有系统的 1 小时和 4 小时的间隔。为什么你想要简登录的 11:10 值,而不是 12:10 等? f1/1,3_f2/1,4_f3/1,5 符号是什么?
  • 请将该信息添加到问题中。这极大地使处理复杂化。获取“它们”以停止与输出格式不一致。它使生活变得地狱。我想知道制作这种布局付出了多少努力?并且“值”似乎意味着类似名称的列,因为时间和操作都不一定相同。你对格式有什么意见吗?
  • “我尝试了几种方法,但没有一种方法适合我。”糟糕,您忘记发布代码了。 StackOverflow 旨在帮助人们修复他们的代码。这不是免费的编码服务。任何代码都比没有代码好。祝你好运;-/
  • 请编辑问题!!!为什么*Dorothy*Mark> 不出现在输出中?包含或排除人员的标准是什么?如果无关紧要,为什么输出包含“操作”信息?输出中应该包含哪个操作?为什么输出包含时间值?应该包括哪个时间价值?为什么输出有时包含序列号,有时不包含?处理它是痛苦的。为什么*Bob>*Jane> 在输出中出现多次?这样做有什么好处?
  • 显然@JonathanLeffler 对Please add that information to the question 和后来的Please EDIT THE QUESTION!!! 的建议并不清楚。请问好看吗?假设您需要帮助 - 没有人愿意通过一堆 cmet 试图拼凑信息和要求,因此如果您将所有信息和要求放在一个地方并听取 cmet 的意见,您就有更好的机会获得帮助。

标签: file awk compare text-processing


【解决方案1】:

这样的?

 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

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

【讨论】:

  • 在参数列表中使用了两次文件f1,因此不需要 END 块。这几乎和问题一样难以理解,所以这是一个合适的答案。
  • 有没有办法让文件/id 在同一个 id 上找到时不存在
  • 我不明白你的问题。该脚本使用第一个文件条目作为键。
【解决方案2】:

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

script.awk

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]
            }
          }

解释:

  • 记录当前文件名,并在名称更改时重置逻辑行号。
  • 对于第一个文件中的行:
    • 在由物理行号(FNR — 文件记录号)索引的行数组中记录行。
    • 跟踪最长的输入行
    • 如果字段数为4,记录名称存在,并且出现在物理行号上
  • 对于具有 4 个字段的行(在所有文件中),它:
    • 增加逻辑行号
    • 如果名称是第一个文件中的一个,则检查该名称是否已在当前文件中看到 (names_in_file)
    • 如果不是,则在data[name] 非空时添加下划线并将文件名、斜杠和逻辑行号添加到data[name]
    • 否则将逗号和逻辑行号添加到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
$

【讨论】:

    猜你喜欢
    • 2013-08-20
    • 2013-04-27
    • 2012-10-15
    • 1970-01-01
    • 2010-10-25
    • 2015-01-15
    • 1970-01-01
    相关资源
    最近更新 更多