if grep -Fqvf file2 file1; then
echo $"There are lines in file1 that don’t occur in file2."
fi
Grep选项意味着:
-F, --fixed-strings PATTERN is a set of newline-separated fixed strings
-f, --file=FILE obtain PATTERN from FILE
-v, --invert-match select non-matching lines
-q, --quiet, --silent suppress all normal output
readarray -t terms < file1 # bash
# zsh: terms=("${(@f)$(< file1)}")
for term in "${terms[@]}"; do # I know `do` "should" be on a separate line; bite me
grep -Fq "$term" file2 ||
{ echo "$term does not appear in file2" && break }
done
3条答案
按热度按时间2admgd591#
Grep选项意味着:
nbnkbykc2#
你可以试试
其中
a.awk
为cotxawn73#
这篇文章的最高投票答案
grep -Fqvf file2 file1
并不完全正确;这方面有若干问题,所有这些问题都源于一个主要问题:也就是说,比较的方向是相反的。我们使用file2
中的每一行来搜索file1
,以确保file1
中的所有行都被覆盖。这符合grep的工作方式,非常优雅,但实际上并没有解决问题。我在比较两个包列表时发现了这一点--一个是pacman -Qqe
的输出,另一个是我把这些软件包编译成不同的组以简化安装新电脑的过程,我想确保我没有遗漏任何组中的软件包。第一个问题是主要的--如果
file2
包含一个空行,输出将 * 总是 * 为false(即,它不会识别出有缺失的行),这是因为file2
中的空行将匹配file1
的每一行,所以对于以下文件,我们不能正确识别出zsh
在file2
中缺失:好吧,我们可以去掉空行,对吧?
很好!但是现在我们遇到了另一个问题。假设我们从
file2
中删除yaourt
。但这是我们实际得到的
为什么会这样呢?嗯,这和空行导致问题的原因是一样的。在这个例子中,
file2
中的r
行与file1
中的yaourt
匹配。删除空行只解决了这个更普遍问题中最严重的情况。除了这里的假阴性,还有由于没有处理OP提出的案例而导致的假阳性--
值得注意的是,虽然
file1
每行有一个搜索项,但这些搜索项可以出现在file2
中的任何位置,包括单词的中间。这就意味着如果
ohmyzsh
在file2
中,那么zsh
就在file1
中匹配,但这不会发生,因为我们在file1
中搜索ohmyzsh
,显然,zsh
不匹配,假设它是ohmyzsh
的子串。最后一个例子说明了为什么用file2
的行来搜索file1
是行不通的。但是如果我们用file1
的行来搜索file2
,我们将得到file2
中的所有匹配项,但不知道是否对file1
的每一行都有匹配项。匹配项的数量没有帮助,因为我们可能对sh
(zsh
,bash
,fish
,...)有多个匹配项,但对acpi
没有匹配项。这意味着这不是一个O(1)greps可以解决的问题,你需要使用一个循环,而使用循环,这个问题是微不足道的。