我有 2 个文件,都有很多行,但只包含一个数字。我试图查看 file1 中的任何数字是否与 file2 中的数字匹配。这是我尝试过的,但由于某种原因它不起作用:
for i in $(cat file1); do grep ${i} file2; done
这里的前参考是来自 file1 和 file2 的数据
file1 file2
2134 1251
2135 5626
5342 4327
6456 8453
3413 4537
4525 3533
2347 5738
1235 1235
7453 3462
那么这个命令不应该获取文件 1 中的每一行并将其与整个文件 2 进行 grep 吗?在这种情况下,不应该在屏幕上打印匹配吗?
答案1
您只需要使用grep -f file1 file2
或者您也可以使用cat file1 | grep -f /dev/stdin file2
答案2
给定两个普通的 Unix 文本文件,你的 shell 循环会打印
1235
因为这是两个文件中都出现的行。如果没有,那么您的文件之一可能是 DOS 文本文件。您可以使用该实用程序将 DOS 文本文件转换为 Unix 文本文件dos2unix
。
考虑到您拥有的数据类型,您的循环没有什么重大问题,除了它调用grep
一次 for每一个行在file1
.它还会匹配子字符串,例如100
in 1001
,并且如果任何行包含file1
空格或制表符,它会将这些行拆分为多个单词(因为其中for i in $(cat ...)
未$(cat ...)
加引号)。
如果您想解决您的问题这方式(带循环),你最好这样做
while IFS= read -r word; do
grep -xF -e "$word" file2
done <file1
和稍后在我的回答中进行解释,并表示下一个参数是要匹配的模式(否则,如果它以破折号()开头,则可以将其视为命令行-x
选项。-F
-e
-
这仍然会grep
为 中的每一行执行一次file1
,但它会正确执行。
要提取与file2
in 中的行完全对应的行file1
,而不使用 shell 循环,您可以使用
$ grep -xF -f file1 file2
1235
这是假设file1
包含一个合理的行数,但不要太多(“太多”将取决于您拥有的内存量)。
该命令使用grep
with -x
,它强制仅跨整行进行匹配(无子字符串匹配),并且 with-F
进行更改grep
以进行字符串比较而不是正则表达式匹配。
指示从 读取模式(要匹配-f file1
的grep
字符串)file1
。
对于真正大量的数据,使用效率会非常低grep
。相反,对于此任务和这种类型的数据(单独行上的单个单词),最好在文件之间执行关系连接操作:
$ join file1 file2
1235
这个会,假设两个文件均按字典顺序排序,返回两个文件之间相同的数字。
使用comm
:
$ comm -1 -2 file1 file2
1235
comm
还比较已排序文件并可以轻松处理非常大型数据集。它默认打印三列:
- 仅出现在第一个文件中的行
- 仅出现在第二个文件中的行
- 两个文件中都出现的行
我们-1
关闭第一列的输出,并-2
禁用第二列,只comm
输出两个文件中相同的行。