我用来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