grep 文件时如何从第一个文件中 grep 不匹配的行?

grep 文件时如何从第一个文件中 grep 不匹配的行?

我用来grep查找两个文件之间的匹配行。

grep -w -f file1.txt file2.txt > file3.txt

我知道有一个-v标志可以为我提供与file2.txt中不匹配的行file1.txt.有没有办法从 中获取file1.txt不匹配的行file2.txt?交换它们的位置是行不通的,因为file2.txt每行都有更多文本。

本质上,file1.txt是一个包含单列 ID 且没有任何空格的文本文件,而file2.txt是一个表,其中各列用制表符分隔,并且一列具有类似于 中的 ID file1.txt。所以我试图找到的是file2.txt中没有匹配 ID的行file1.txt

事实上,现在我想我已经在另一个问题中找到了答案: “Ungrep” - 哪些模式不匹配

答案1

这个答案是 @danvoronov 的初始帖子和 @waltinator 获取未使用密钥的解决方案的组合,并对两者进行了改进。

我有大约 60 行 Bash 和 awk,它们使用普林斯顿 CS50 课程材料中的英语语言集中的随机选择来构建测试文件。我还有 30 行 Bash 和 awk,可以在单个进程中解决这个问题。这需要性能改进,所以我还不会发布它。

我的脚本和下面发布的脚本产生相同的结果。出于参考和检查目的,每个输出文本前面都有原始文件中的行号。测试文件由 file1 中的 15000 条较短记录(12000 条与 file2 匹配,3000 条不匹配,平均长度 92 个字符)和 file2 中的 20000 个完整行(平均长度 129 个字符)组成。

密钥是从较大记录的随机选择中获取的,从行中的随机单词开始获取随机数量的单词(但至少四个)。

请注意,单个键可以匹配多个记录。我们不尝试强制一对一配对。

下面发布的脚本在该数据量上运行大约需要 1 分 30 秒(我的 awk 需要 5 分 45 秒)。

file1 中的数据不太可能是有效的正则表达式,因此必须在 grep 中使用 -F 选项。如果将纯文本视为 RE,则许多字符如 * + 。会意外匹配,其他如 ( ) [ ] |会抛出错误。 -F 也可以更快(我发现了 600 倍的改进——我想知道那个算法是什么!)。

未使用键的 grep 仅使用 -q 选项,状态显示是否发生匹配。这节省了两个进程(file1 中每一行的一个子 shell 和一个 wc -l),平均而言,它还将读取的数据减半,因为它在第一次匹配时退出,而不是读取整个文件。

#! /bin/bash

    grep -n -w -F -f file1.txt file2.txt > file3.txt

    while read -r Key; do
        (( ++Fnr ))
        grep -q -w -F -- "$Key" file2.txt || printf '%d:%s\n' "${Fnr}" "$Key"
    done < file1.txt > file4.txt

由于一些最初的问题尚未得到解答(数据是否在字段中、空格是否重要、数据量有多大),欢迎发表评论。

答案2

单独处理以下行file1.txt

for str in $(cat file1.txt) ; do
    num=$(grep -w "$str" file2.txt | wc -l )
    if [[ $num -eq 0 ]] ; then
        echo "$str"
    fi
done

相关内容