检查文件的整个原始文本内容作为另一个文件的一部分存在
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
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