【发布时间】:2019-08-20 20:18:22
【问题描述】:
我有两个任意文件:
==> file1 <==
11110 abcdef
11111 apple
11112 banana
11113 carrot
11114 date
11115 eggplant
==> file2 <==
11110 abcdefg
11111 apple-pie
11112 banana-cake
11113 chocolate
11115 egg
11116 fruit
为了比较这些文件,我只关心第一列的数字,break后面的单词不重要。
我希望能够轻松识别每个文件中缺少的数字。
例如,文件 1 没有 11116,文件 2 没有 11114。
如果我将文件排序在一起,我可以得到一个完整的列表:
$ sort file*
11110 abcdef
11110 abcdefg
11111 apple
11111 apple-pie
11112 banana
11112 banana-cake
11113 carrot
11113 chocolate
11114 date
11115 egg
11115 eggplant
11116 fruit
我可以通过 uniq 运行它并仅比较数字的长度来获得所有数字的列表:
$ sort file* | uniq -w5
11110 abcdef
11111 apple
11112 banana
11113 carrot
11114 date
11115 egg
11116 fruit
这是所有数字 11110-11116 的列表。
我可以通过要求 uniq 为我过滤它们来获得唯一和重复的列表:
重复(出现在两个文件中的数字):
$ sort file* | uniq -dw5
11110 abcdef
11111 apple
11112 banana
11113 carrot
11115 egg
唯一的数字,或只出现在一个文件中的数字:
$ sort file* | uniq -uw5
11114 date
11116 fruit
我想要一些输出类似于:
# shows numbers that do not exist in this file
$ sort file* | <is missing>
==> file1 <==
11116 fruit
==> file2 <==
11114 date
它可以做相反的事情并显示 OTHER 文件中缺少哪些数字,每种情况都是可行的:
# shows numbers that do exist ONLY in this file
$ sort file* | <has unqie>
==> file1 <==
11114 date
==> file2 <==
11116 fruit
第一个字段将包含约 30 个字母数字字符。
有问题的文件包含数千个条目,并且大多数条目预计都在这两个文件中。
数字右边的任意数据是相关的,需要保留。
我的想法是:
- 生成完整的数字列表
- 将该列表与 file1 进行比较以搜索唯一条目
- 将该列表与 file2 进行比较以搜索唯一条目
但我不知道如何在一行中做到这一点:
sort file* | uniq -w5 | sort file1 | uniq -uw5
sort file* | uniq -w5 | sort file2 | uniq -uw5
但是,第一个 uniq 的输出并没有与 file1/2 的使用合并...
我想出的解决方案是创建所有数字的输出:
$ sort file* | uniq -w5
然后对每个文件单独运行它,这确实有效。我只是无法将它拼凑成一行:
$ sort all file1 | uniq -uw5
11116 fruit
$ sort all file2 | uniq -uw5
11114 date
我现在正在合并加入,谢谢卡米尔
编辑:我自己从来没有走得更远,@Shawn 用很短的一行就给了我:
join -j1 -v1 file1 file2
在我有两个我需要的格式的编译列表后,对文件执行的join 会吐出所需的答案。从我上面的代码示例中:
$join -j1 -v1 file1 file2
11114 date
$ join -j1 -v2 file1 file2
11116 fruit
真实世界示例:
我想我会生成一个真实世界的例子来说明我一直在做的事情。取 5 个任意文件:
lorem1.txt
lorem2.txt
lorem3.txt
lorem4.txt
lorem5.txt
并对它们进行备份。我在lorem2.txt 中修改了一点,并从备份中删除了`lorem4.txt(认为它是一个新文件,或者无论出于何种原因,它只是一个丢失的文件):
test$ tree
.
├── data
│ ├── lorem1.txt
│ ├── lorem2.txt
│ ├── lorem3.txt
│ ├── lorem4.txt
│ └── lorem5.txt
└── data-backup
├── lorem1.txt
├── lorem2.txt
├── lorem3.txt
└── lorem5.txt
2 directories, 9 files
mad@test$ md5deep data/* | sort > hash1
mad@test$ md5deep data-backup/* | sort > hash2
mad@test$ head hash*
==> hash1 <==
44da5caec444b6f00721f499e97c857a /test/data/lorem1.txt
5ba24c9a5f6d74f81499872877a5061d /test/data/lorem2.txt
a00edd450c533091e0f62a06902545a4 /test/data/lorem5.txt
b80118923d16f649dd5410d54e5acb2d /test/data/lorem4.txt
fb8f7f39344394c78ab02d2ac524df9d /test/data/lorem3.txt
==> hash2 <==
000e755b8e840e42d50ef1ba5c7ae45d /test/data-backup/lorem2.txt
44da5caec444b6f00721f499e97c857a /test/data-backup/lorem1.txt
a00edd450c533091e0f62a06902545a4 /test/data-backup/lorem5.txt
fb8f7f39344394c78ab02d2ac524df9d /test/data-backup/lorem3.txt
运行我们的joins:
加入 1
mad@test$ join -j1 -v1 hash*
5ba24c9a5f6d74f81499872877a5061d /test/data/lorem2.txt
b80118923d16f649dd5410d54e5acb2d /test/data/lorem4.txt
从我们的两组哈希文件中,joining 他们针对第一个文件进行了验证,我们看到 lorem2.txt 和 lorem4.txtare missing from the second file. (lorem2because we changed a bit, andlorem4 的匹配哈希,因为我们没有复制,或者我们从备份中删除了文件)。
做reverse join可以看到lorem2存在,只是hash不正确:
加入 2
mad@test$ join -j1 -v2 hash*
000e755b8e840e42d50ef1ba5c7ae45d /test/data-backup/lorem2.txt
使用我之前的sort 和uniq 示例,我可以获得类似的结果,但上面的join 要好得多。 join1 向我们展示了我们需要重新访问的文件,join2 专门向我们展示了哪些哈希值不正确。
按名称排序并显示 uniq 名称(这超出了原始问题的范围)可以向我们显示备份中丢失的文件。在此示例中,我转换了备份文件名,以便它们模仿原始文件名,将它们与原始文件名合并/排序,并仅根据名称而不是哈希值进行排序。这将显示备份中缺少的文件:
test$ sort -k2 hash1 <(sed 's/data-backup/data/g' hash2) | uniq -uf1
b80118923d16f649dd5410d54e5acb2d /test/data/lorem4.txt
如果我们有一个包含所有哈希的文件:
test$ sort -k2 hash1 allhashes | uniq -uf1
b80118923d16f649dd5410d54e5acb2d /test/data/lorem4.txt
再次感谢所有帮助我制定此计划的人。它已经变成了一个真正的生命和时间节省者。
【问题讨论】:
-
我们有一立方公里的近乎重复。你能告诉我们你已经搜索过什么以及你找到了什么吗?例如,一个简单的 Awk 脚本应该不难找到。
-
我试图证明我一直在努力。我确实想出了一个的答案,但我不能把它放在一行中。
-
man join。加入第一个字段并从两个文件中打印不可比较的行。
-
@KamilCuk 很好,谢谢,我不知道加入!
-
特别是,假设文件已排序,
join -j1 -v1 file1 file2将打印仅在 file1 中的记录,join -j1 -v2 file1 file2将仅在 file2 中打印记录。