提取2个集/文件之间的唯一值

mar*_*ark 24 linux bash scripting perl command-line

在linux/shell环境中工作,我该如何完成以下任务:

文本文件1包含:

1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

文本文件2包含:

6
7
1
2
3
4
Run Code Online (Sandbox Code Playgroud)

我需要提取文件2中不在文件1中的条目.因此在本例中为'6'和'7'.

我如何从命令行执行此操作?

非常感谢!

Sie*_*geX 51

$ awk 'FNR==NR {a[$0]++; next} !a[$0]' file1 file2
6
7
Run Code Online (Sandbox Code Playgroud)

代码如何工作的说明:

  • 如果我们正在处理file1,请跟踪我们看到的每一行文本.
  • 如果我们正在处理file2,并且没有看到行文本,那么打印它.

细节说明:

  • FNR 是当前文件的记录号
  • NR 是所有输入文件的当前总记录数
  • FNR==NR 只有当我们读取file1时才是真的
  • $0 是当前的文本行
  • a[$0] 是一个哈希,键设置为当前文本行
  • a[$0]++ 跟踪我们已经看到的当前文本行
  • !a[$0] 只有当我们没有看到行文本时才是真的
  • 如果上述模式返回true,则打印文本行,这是未给出显式操作时的默认awk行为

  • 只是为了记录,这种技术虽然有效,但将为第一个文件中不存在的所有第二个文件条目创建 `a[$0]` 内存位置。如果第二个文件有一百万行,这个解决方案就不是最好的。另一方面,`$0 in a` 方法会检查是否存在,但不会为第二个文件条目创建额外的内存位置。 (2认同)

Dan*_*her 16

使用一些鲜为人知的实用程序:

sort file1 > file1.sorted
sort file2 > file2.sorted
comm -1 -3 file1.sorted file2.sorted
Run Code Online (Sandbox Code Playgroud)

这将输出重复项,因此如果有1 3in file1,但是2 in file2,这仍然会输出1 3.如果这不是你想要的,从输出管道sort通过uniq其写入文件之前:

sort file1 | uniq > file1.sorted
sort file2 | uniq > file2.sorted
comm -1 -3 file1.sorted file2.sorted
Run Code Online (Sandbox Code Playgroud)

GNU coreutils包中有许多实用程序,允许进行各种文本操作.

  • 很好地呼吁这些公用事业.您可以将它组合成一个更简单的形式,并删除对临时文件的需求:`comm -13 <(sort file1)<(sort file2)`我仍然更喜欢`awk`,因为它只运行一个进程而不是3不需要排序的文件.这可以对大文件产生很大的影响. (6认同)
  • `join`也可以用于此. (3认同)

xeb*_*che 8

我想知道以下哪个解决方案是"更大"的"更大"文件:

awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2 # awk1 by SiegeX
awk 'FNR==NR{a[$0]++;next}!($0 in a)' file1 file2          # awk2 by ghostdog74
comm -13 <(sort file1) <(sort file2)
join -v 2 <(sort file1) <(sort file2)
grep -v -F -x -f file1 file2
Run Code Online (Sandbox Code Playgroud)

我的基准测试结果简而言之:

  • 不要使用grep -Fxf,它要慢得多(在我的测试中是2-4倍).
  • comm比...快一点join.
  • 如果file1和file2已经排序,comm并且join比awk1 + awk2快得多.(当然,他们不会假设已排序的文件.)
  • 据推测,awk1 + awk2使用更多的RAM和更少的CPU.实际运行时间较低comm可能是因为它使用了更多线程.awk1 + awk2的CPU时间较短.

为简洁起见,我省略了完整的细节.但是,我认为有兴趣的人可以联系我或者只是重复测试.粗略地说,设置是

# Debian Squeeze, Bash 4.1.5, LC_ALL=C, slow 4 core CPU
$ wc file1 file2
  321599   321599  8098710 file1
  321603   321603  8098794 file2
Run Code Online (Sandbox Code Playgroud)

最快运行的典型结果

awk2: real 0m1.145s  user 0m1.088s  sys 0m0.056s  user+sys 1.144
awk1: real 0m1.369s  user 0m1.324s  sys 0m0.044s  user+sys 1.368
comm: real 0m0.980s  user 0m1.608s  sys 0m0.184s  user+sys 1.792
join: real 0m1.080s  user 0m1.756s  sys 0m0.140s  user+sys 1.896
grep: real 0m4.005s  user 0m3.844s  sys 0m0.160s  user+sys 4.004
Run Code Online (Sandbox Code Playgroud)

顺便说一句,对于awkies:它看起来a[$0]=1比速度更快a[$0]++,而且(!($0 in a))速度更快(!a[$0]).因此,对于awk解决方案,我建议:

awk 'FNR==NR{a[$0]=1;next}!($0 in a)' file1 file2
Run Code Online (Sandbox Code Playgroud)

  • 出色的基准测试、结果和优化。谢谢你! (2认同)

sid*_*com 5

用grep:

grep -F -x -v -f file_1 file_2 
Run Code Online (Sandbox Code Playgroud)


Ivo*_*Ivo 5

怎么样:

diff file_1 file_2 | grep '^>' | cut -c 3-
Run Code Online (Sandbox Code Playgroud)

这将打印file_2中不在file_1中的条目.对于相反的结果,只需要用'<'替换'>'.'cut'删除'diff'添加的前两个字符,这些字符不是原始内容的一部分.

甚至不需要对文件进行排序.