检查文件的所有行是否都出现在不同的文件中


14

我得到两个文件:大约1万行的file1和几百行的file2。我想检查file2的所有行是否都出现在file1中。即:∀行ℓ∈file2:∀∈file1

任何人都不应该知道这些符号是什么意思,或者“检查file2的所有行是否在file1中出现”的含义是:两个文件中的几个等效行都不影响检查是否返回文件满足要求。

我该怎么做呢?


2
那些文件可以重复吗?如果file2包含2行A,您是否需要file1至少包含2行A
斯特凡Chazelas

2
@StéphaneChazelas确保所有行(在两个文件中)都是唯一的。
UTF-8

1
@ UTF-8这将是编辑您的问题的重要细节。
David Z

2
@DavidZ不再,因为现有的答案不再依赖于该保证。因此,通过立即编辑问题,我将缩小答案的明显范围。
UTF-8

@ UTF-8我想是这样,尽管没有这个问题还是有点模棱两可,例如,如果给定的一行在file2中出现5次,那该行是否也必须在file1中出现5次(而不是仅出现一次)?如果您有此要求,那么看起来任何现有的答案都行不通,因此,我建议至少进行一些编辑,使其清楚地表明那不是您的意思。
David Z

Answers:


18
comm -13 <(sort -u file_1) <(sort -u file_2)

此命令将输出特有的行file_2。因此,如果输出为空,则所有file_2行都包含在中file_1

来自通讯员的男人:

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

@don_crissti是的。固定:-u添加到sort命令中的选项。现在,两个排序文件中只剩下唯一的行。
MiniMax

简直就是解决方案!此语法适用于任何需要文件的程序吗?我一直以为<管道输入标准输入。括号项会改变这一点吗?
UTF-8

2
@ UTF-8称为流程替换。您可以在此处阅读有关内容。是的,它的行为就像一个临时文件,因此可以在任何需要文件的程序中使用它代替实际文件。
MiniMax

如果您经常这样做,则可能要以file_1预分类的形式存储。节省打字和时间。
Stig Hemmer'17-10-13

7
@minimax除了“任何”以外,其他都很好。进程替换虽然很棒,但是不能在所有情况下使用,因为生成的“文件”是流而不是实际文件。这意味着它们不像普通文件那样“可搜索”,并且仅当程序从头开始正常读取文件时才可以使用它们,而当程序使用某些仅文件功能(例如搜寻特定点或倒带从头开始。幸运的是,大多数程序仅读取()他们的文件,因此进程替换适用于大多数程序,但不适用于“任何”程序。
法律29年

7
[ $(grep -cxFf file2 <(sort -u file1)) = $(sort -u file2 | wc -l) ] && 
  echo all there || 
  echo some missing

如果file1中(唯一行)中file2的匹配数目与file2中唯一行的数目相同,则它们全部存在;否则,事实并非如此。


5

awk在确实支持特定length(array)功能(以及其他awk可能支持的其他实现)的地方使用GNU ,如果文件已排序,则不需要。

gawk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{print (!length(seen))?"Matched":"Not Matched"}' file2 file1

会将file2读入一个seen以key作为file2整行的数组。

然后读取file1,如果每行与看到的数组中的行匹配,则删除该键。

最后,如果数组为空,则表示file2中的所有行都在file1中并且将打印Matched,否则将显示Not Matched


为了awk实现所有实现的兼容性。

awk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{for(x in seen);print (!x)?"Matched":"Not Matched"}' file2 file1

若要仅在file2中忽略空行或带有空格的行,则需要添加NF条件,NR==FNR && NF {...以跳过将其读入数组的操作。


length(array)仅适用于gawk的AFAIK;绝对不是POSIX。
dave_thompson_085

@ dave_thompson_085正确,我已经更新了答案。感谢
αғsнιη

3

使用comm可以找到两个文件中共有的行。

comm -12 file1 file2

看看man comm更多细节


纠正它在两个文件中都返回公共行的问题,但这不能提供OP的Q答案,如果您在file2中有一行没有在file1中退出,那么file2的所有行都不在file1中。
αғsнιη

1
文件应排序。来自man“ comm-逐行比较两个排序的文件”。
MiniMax

@MiniMax是正确的。这行不通。另一个利用答案的方法comm显然不是错误的。当我运行您的命令时,我收到警告,指出文件未排序,并且肯定在两个文件中都有很多行。
UTF-8

3
diff -q <(sort -u file2) <(grep -Fxf file2 file1 | sort -u)

如果不会产生任何输出file1包含所有行file2,并用状态退出0,否则将打印像

Files /proc/self/fd/11 and /proc/self/fd/12 differ

并退出状态 1


2

使用Python程序:

#!/usr/bin/env python3
import sys

def open_arg(path):
    return sys.stdin if path == '-' else open(path)

def strip_linebreak(s):
    return s[:-1] if s.endswith('\n') else s

with open_arg(sys.argv[1]) as pattern_file:
    patterns = set(map(strip_linebreak, pattern_file))

with open_arg(sys.argv[2]) as dataset_file:
    for l in map(strip_linebreak, dataset_file):
        patterns.remove(l)
        if not patterns:
            break

sys.exit(int(bool(patterns)))

用法:

python3 contains-all.py file2 file1

程序退出状态指示文件2的所有模式是否都匹配:

  • 0(成功)表示所有模式都匹配。
  • 1(失败)表示某些模式不匹配。

要查询在shell(脚本)的退出状态,你可以使用$?特殊的变量或计算结果命令的退出状态其他表达式,如短路运营商&&||和条件表达式像ifwhile。例:

if python3 compare-all.py file2 file1 && some-other --condition; then
    # do stuff
fi

1

combinemoreutils会告诉你所有的线file2不在file1同:

combine file2 not file1

然后,您可以将其管道输送到来计算行数wc -l,例如:

if [ $(combine file2 not file1 | wc -l) != 0 ]; then
  echo "lines missing"
else
  echo "You're fine"
fi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.