繁体   English   中英

按bash中的字段比较文件

[英]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个字母数字字符。

有问题的文件包含数千个条目,并且大多数条目都应在两个文件中。

数字右边的任意数据是相关的,需要保留。

我有以下想法:

  • 生成数字的完整列表
  • 将列表与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中的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

用我的sortuniq例子从早期的,我能得到类似的结果,但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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM