检查文件的整个原始文本内容作为另一个文件的一部分存在

Check file's whole raw text content exists as part of another file

big1.txt:

a
b
c
d
e

big2.txt:

f
c
g
h
i
b

small.txt:

b
c

在 bash 脚本中,如何判断 small.txt 的全部有序内容存在于另一个文件中?

示例:

??? small.txt big1.txt 应该 return true

??? small.txt big2.txt 应该 return false

请检查这个

if perl -0777 -e '$n = <>; $h = <>; exit(index($h,$n)<0)' small.txt big.txt
then echo small.txt is found in big.txt
fi

如果big1.txt和big2.txt不是太大(可以加载到内存中)。以下测试可能就足够了。

# to store file content into variables
big1=$(< big1.txt)
big2=$(< big2.txt)
small=$(< small.txt)

# to run from test case
big1=$'a\nb\nc\nd\ne\n'
big2=$'f\nc\ng\nh\ni\nb\n'
small=$'b\nc\n'

if [[ ${big1} = *${small}* ]]; then echo "big1"; fi
if [[ ${big2} = *${small}* ]]; then echo "big2"; fi

有时发现两个复杂事物 'equal' 的方法是做一些简单的测试,如果它们相等则为真,否则很少为真。那些通过这个启发式测试的人会被更仔细地检查......但很少有完全平等测试可能很昂贵而且不会在每次比较时触发。

在这种情况下我会做的是获取所有文件,然后对它们的行进行排序。 (如果您正在寻找匹配的文本,您可能希望抑制空白行,并去除带有尾随空白的行,但这是您的选择)。可能对删除重复行有用。

现在将每个文件与所有更长的文件进行比较,看它是否是前缀。 (如果另一个文件更短,则不能作为前缀,因此我们摆脱了 1/2 仅基于大小的比较)。如果排序后的文件 A 是排序后的文件 B 的前缀,那么您可以 运行 进行更复杂的测试,以查看真实文件 A 是否嵌入在文件 B 中(我怀疑如果排序后的文件很有可能是真的通过前缀测试)。

有了这个想法,我们现在可以优化它。我们不是存储文本行,而是获取每个文件,并对每一行进行哈希处理,给出一个哈希码文件。排序这些。按照其余步骤进行操作。

下一个技巧:确定我们的散列码大小为 8 位或 16 位。这使它们适合您最喜欢的编程语言的特性。现在,您的前缀比较测试可以包括收集每个文件的字符大小的散列码,并对较短的和较长的进行字符串比较。在这一点上,我们已经将问题从读取磁盘转移到在内存中进行有效比较;我们可能无法加快速度,因为与内存计算相比,磁盘读取非常昂贵。

$ diff small big1.txt | grep -q '^<'
$ echo $?
1

$ diff small big2.txt | grep -q '^<'
$ echo $?
0

$ ! (diff small big1.txt | grep -q '^<')
$ echo $?
0

$ ! (diff small big2.txt | grep -q '^<')
$ echo $?
1

$ if diff small big1.txt | grep -q '^<'; then echo "does not exit"; else echo "does exist"; fi
does exist

$ if diff small big2.txt | grep -q '^<'; then echo "does not exit"; else echo "does exist"; fi
does not exit