如何检查一个文件是否是其他的一部分?

我需要通过bash脚本来检查一个文件是否在另一个文件中。 对于给定的多行模式和input文件。

返回值:

我想接收状态(如何在grep命令)0如果find任何匹配,1如果没有find匹配。

模式:

  • 多,
  • 行的顺序是重要的(被视为一个单独的行)
  • 包括数字,字母,?,&,*,#等字符,

说明

只有下面的例子应该find匹配:

pattern file1 file2 file3 file4 222 111 111 222 222 333 222 222 333 333 333 333 444 444 

以下不应该:

 pattern file1 file2 file3 file4 file5 file6 file7 222 111 111 333 *222 111 111 222 333 *222 222 222 *333 222 222 333 333* 444 111 333 444 333 333 

这是我的脚本:

 #!/bin/bash function writeToFile { if [ -w "$1" ] ; then echo "$2" >> "$1" else echo -e "$2" | sudo tee -a "$1" > /dev/null fi } function writeOnceToFile { pcregrep --color -M "$2" "$1" #echo $? if [ $? -eq 0 ]; then echo This file contains text that was added previously else writeToFile "$1" "$2" fi } file=file.txt #1?1 #2?2 #3?3 #4?4 pattern=`cat pattern.txt` #2?2 #3?3 writeOnceToFile "$file" "$pattern" 

我可以对所有的模式使用grep命令,但是这个例子失败了:

 file.txt #1?1 #2?2 #=== added line #3?3 #4?4 pattern.txt #2?2 #3?3 

或者即使你换线:2与3

 file=file.txt #1?1 #3?3 #2?2 #4?4 

当不应该返回0时。

我该如何解决它? 请注意,我更喜欢使用本地安装的程序(如果这可以没有pcregrep)。 也许sed或awk可以解决这个问题?

Solutions Collecting From Web of "如何检查一个文件是否是其他的一部分?"

我有一个使用Perl的工作版本。

我以为我使用GNU awk ,但是我没有。 RS =空行分割空行。 查看损坏的awk版本的编辑历史记录。

如何在文件中搜索多行模式? 展示了如何使用pcregrep,但是当搜索模式可能包含正则表达式特殊字符时,我看不到一种方法来使其工作。 -F固定字符串模式不适用于多行模式:它仍然将模式视为一组要分别匹配的行。 (不是作为一个多行固定字符串来匹配。)我看你已经在你的尝试中使用pcregrep。

顺便说一句,我认为你的代码在非sudo的情况下有一个错误:

 function writeToFile { if [ -w "$1" ] ; then "$2" >> "$1" # probably you mean echo "$2" >> "$1" else echo -e "$2" | sudo tee -a "$1" > /dev/null fi } 

无论如何,使用基于行的工具的尝试都遇到了失败,所以现在是时候推出一个更严格的编程语言,而不会强制我们使用新行规范。 只要将这两个文件读入变量,并使用非正则表达式搜索:

 #!/usr/bin/perl -w # multi_line_match.pl pattern_file target_file # exit(0) if a match is found, else exit(1) #use IO::File; use File::Slurp; my $pat = read_file($ARGV[0]); my $target = read_file($ARGV[1]); if ((substr($target, 0, length($pat)) eq $pat) or index($target, "\n".$pat) >= 0) { exit(0); } exit(1); 

请参阅在Perl中将文件转换为字符串的最佳方法是什么? 避免依赖于File::Slurp (这不是标准的perl发行版或默认的Ubuntu 15.04系统的一部分)。 我为File :: Slurp去了部分可读性的程序正在做什么,非per-geeks,相比之下:

 my $contents = do { local(@ARGV, $/) = $file; <> }; 

我正在努力避免阅读完整的文件到内存中,从http://www.perlmonks.org/?node_id=98208的想法&#x3002; 我认为不匹配的案例通常会一次读取整个文件。 而且,处理文件前面的匹配的逻辑非常复杂,我不想花太多时间进行测试,以确保对所有情况都是正确的。 这就是我放弃之前所拥有的:

 #IO::File->input_record_separator($pat); $/ = $pat; # pat must include a trailing newline if you want it to match one my $fh = IO::File->new($ARGV[2], O_RDONLY) or die 'Could not open file ', $ARGV[2], ": $!"; $tail = substr($fh->getline, -1); #fast forward to the first match #print each occurence in the file #print IO::File->input_record_separator while $fh->getline; #FIXME: something clever here to handle the case where $pat matches at the beginning of the file. do { # fixme: need to check defined($fh->getline) if (($tail eq '\n') or ($tail = substr($fh->getline, -1))) { exit(0); # if there's a 2nd line } } while($tail); exit(1); $fh->close; 

另一个想法是通过tr '\n' '\r'或者其他东西过滤要搜索的模式和文件,所以它们都是单行的。 ( \r是一个可能的安全选择,不会与已经存在于文件或模式中的任何东西相冲突。)

我只是用diff来完成这个任务:

 diff pattern <(grep -f file pattern) 

说明

  • diff file1 file2报告两个文件是否有区别。

  • 通过说grep -f file pattern你可以看到grep -f file pattern有什么样的内容。

所以你在做的是检查pattern中的哪些行在file ,然后将其与pattern本身进行比较。 如果它们匹配,则意味着该patternfile一个子集!

测试

seq 10seq 20一部分! 我们来检查一下:

 $ diff <(seq 10) <(grep -f <(seq 20) <(seq 10)) $ 

seq 10不完全在seq 2 20 (1不在第二个):

 $ diff -q <(seq 10) <(grep -f <(seq 2 20) <(seq 10)) Files /dev/fd/63 and /dev/fd/62 differ 

我又经历了这个问题,我认为awk可以更好地处理这个问题:

 awk 'FNR==NR {a[FNR]=$0; next} FNR==1 && NR>1 {for (i in a) len++} {for (i=last; i<=len; i++) { if (a[i]==$0) {last=i; next} } status=1} END {print status+0}' file pattern 

这个想法是: – 读取数组中a[line_number] = line所有文件file a[line_number] = line 。 – 计算数组中的元素。 – 循环访问文件pattern并检查当前行是否出现在file中光标所在的位置和文件file结尾之间的任何时候。 如果匹配,则将光标移动到找到的位置。 如果没有,请将状态设置为1 – 也就是说,在上一次匹配之后, file没有出现一行pattern 。 – 打印状态,这将是0除非它之前被设置为1

测试

他们确实匹配:

 $ tail fp ==> f <== 222 333 555 ==> p <== 222 333 $ awk 'FNR==NR {a[FNR]=$0; next} FNR==1 && NR>1{for (i in a) len++} {for (i=last; i<=len; i++) {if (a[i]==$0) {last=i; next}} status=1} END {print status+0}' fp 0 

他们不:

 $ tail fp ==> f <== 333 222 555 ==> p <== 222 333 $ awk 'FNR==NR {a[FNR]=$0; next} FNR==1 && NR>1{for (i in a) len++} {for (i=last; i<=len; i++) {if (a[i]==$0) {last=i; next}} status=1} END {print status+0}' fp 1 

随着seq

 $ awk 'FNR==NR {a[FNR]=$0; next} FNR==1 && NR>1{for (i in a) len++} {for (i=last; i<=len; i++) {if (a[i]==$0) {last=i; next}} status=1} END {print status+0}' <(seq 2 20) <(seq 10) 1 $ awk 'FNR==NR {a[FNR]=$0; next} FNR==1 && NR>1{for (i in a) len++} {for (i=last; i<=len; i++) {if (a[i]==$0) {last=i; next}} status=1} END {print status+0}' <(seq 20) <(seq 10) 0