![](/img/trans.png)
[英]BASH - Comparing two files and redirecting the output to something readable
[英]comparing files by fields in bash
我有两个任意文件:
==> 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
为了比较这些文件,我只关心第一列中的数字,中断后的单词并不重要。
我希望能够轻松识别每个文件中缺少的数字。
例如,文件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个字母数字字符。
有问题的文件包含数千个条目,并且大多数条目都应在两个文件中。
数字右边的任意数据是相关的,需要保留。
我有以下想法:
但是我无法找出如何单行执行此操作:
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
中的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
运行我们的join
s:
参加1
mad@test$ join -j1 -v1 hash*
5ba24c9a5f6d74f81499872877a5061d /test/data/lorem2.txt
b80118923d16f649dd5410d54e5acb2d /test/data/lorem4.txt
从我们的两组哈希文件中, join
它们结合到第一个文件中进行验证,我们发现are missing from the second file. (
lorem2.txt
和lorem4.txt的匹配哈希are missing from the second file. (
are missing from the second file. (
lorem2 because we changed a bit, and
因为我们做because we changed a bit, and
lorem4`是因为我们没有复制,或者我们从备份中删除了文件)。
进行反向lorem2
,我们可以看到lorem2
存在,只是哈希值不正确:
参加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
再次感谢所有帮助我制定此规则的人。 它已经变成了现实生活和时间节省者。
使用gnu awk
,您可以使用以下方法:
awk 'ARGIND < ARGC-1 {
a[ARGIND][$1] = 1
next
} {
for (i=1; i<ARGC-1; i++)
if (!a[i][$1])
print ARGV[i] ":", $0
}' file1 file2 <(sort file1 file2)
file2: 11114 date
file1: 11116 fruit
此awk版本仅对每个文件进行一次遍历:假定文件中没有重复的ID。
awk '
NR == FNR {f1[$1] = $0; next}
!($1 in f1) {printf "only in %s: %s\n", FILENAME, $0}
$1 in f1 {delete f1[$1]}
END {for (id in f1) printf "only in %s: %s\n", ARGV[1], f1[id]}
' file1 file2
输出
only in file2: 11116 fruit
only in file1: 11114 date
仅在file1中:
grep `comm -23 <(cut -d \ -f 1 f1 | sort) <(cut -d \ -f 1 f2 | sort)` f1
您可以在2个文件之间使用diff。 但是,如果您比较这些文件,则将列出所有行。
$ diff file1 file2
1,6c1,6
< 11110 abcdef
< 11111 apple
< 11112 banana
< 11113 carrot
< 11114 date
< 11115 eggplant
---
> 11110 abcdefg
> 11111 apple-pie
> 11112 banana-cake
> 11113 chocolate
> 11115 egg
> 11116 fruit
但是您只关心前导数字。
$ diff <(cut -d' ' -f1 file1) <(cut -d' ' -f1 file2)
5d4
< 11114
6a6
> 11116
如果文件未排序,则添加排序
$ diff <(cut -d' ' -f1 file1 | sort) <(cut -d' ' -f1 file2 | sort)
5d4
< 11114
6a6
> 11116
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.