linux 检查一个文件中的所有行是否都存在于另一个文件中

rqdpfwrv  于 2023-02-21  发布在  Linux
关注(0)|答案(3)|浏览(354)

我使用file1作为file2的数据源,现在我需要确保file1中的每一行文本都出现在file2中的 * 某处 *(并找出哪些行丢失了,如果有的话)。可能需要注意的是,虽然file1每行有一个方便的搜索项,术语可以出现在file2中的 * 任何地方 *,包括单词中间。如果匹配不区分大小写,也会有帮助-只要存在,file2中的文本是否全部大写都无关紧要。
file1中的行包括空格和其他各种特殊字符,如--

2admgd59

2admgd591#

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
nbnkbykc

nbnkbykc2#

你可以试试

awk -f a.awk file1 file2

其中a.awk

BEGIN { IGNORECASE=1 }
NR==FNR {
    a[$0]++
    next
}
{
    for (i in a) 
        if (index($0,i)) 
            delete a[i]
}

END {
    for (i in a)
        print i
}
cotxawn7

cotxawn73#

这篇文章的最高投票答案grep -Fqvf file2 file1并不完全正确;这方面有若干问题,所有这些问题都源于一个主要问题:也就是说,比较的方向是相反的。我们使用file2中的每一行来搜索file1,以确保file1中的所有行都被覆盖。这符合grep的工作方式,非常优雅,但实际上并没有解决问题。我在比较两个包列表时发现了这一点--一个是pacman -Qqe的输出,另一个是我把这些软件包编译成不同的组以简化安装新电脑的过程,我想确保我没有遗漏任何组中的软件包。
第一个问题是主要的--如果file2包含一个空行,输出将 * 总是 * 为false(即,它不会识别出有缺失的行),这是因为file2中的空行将匹配file1的每一行,所以对于以下文件,我们不能正确识别出zshfile2中缺失:

file1                        file2

acpi                         acpi
...                          ...
r                            r
...                          ...
yaourt                       yaourt
zsh                          
<EOF>                        <EOF>

$ grep -Fvf file2 file1
[ no output ]

好吧,我们可以去掉空行,对吧?

$ grep -Fv "$(grep -ve '^&' file2)" file1
zsh

很好!但是现在我们遇到了另一个问题。假设我们从file2中删除yaourt

yaourt
zsh

但这是我们实际得到的

$ grep -Fv "$(grep -ve '^&' file2)" file1
zsh

为什么会这样呢?嗯,这和空行导致问题的原因是一样的。在这个例子中,file2中的r行与file1中的yaourt匹配。删除空行只解决了这个更普遍问题中最严重的情况。
除了这里的假阴性,还有由于没有处理OP提出的案例而导致的假阳性--
值得注意的是,虽然file1每行有一个搜索项,但这些搜索项可以出现在file2中的任何位置,包括单词的中间。
这就意味着如果ohmyzshfile2中,那么zsh就在file1中匹配,但这不会发生,因为我们在file1中搜索ohmyzsh,显然,zsh不匹配,假设它是ohmyzsh的子串。最后一个例子说明了为什么用file2的行来搜索file1是行不通的。但是如果我们用file1的行来搜索file2,我们将得到file2中的所有匹配项,但不知道是否对file1的每一行都有匹配项。匹配项的数量没有帮助,因为我们可能对shzshbashfish,...)有多个匹配项,但对acpi没有匹配项。
这意味着这不是一个O(1)greps可以解决的问题,你需要使用一个循环,而使用循环,这个问题是微不足道的。

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

相关问题