Awk 检查文件中的多行内容

Awk 检查文件中的多行内容,awk,grep,multilinestring,Awk,Grep,Multilinestring,我试图使用公共bash命令grep、awk等检查文件中是否存在多行字符串 我希望有一个包含几行、普通行、而不是模式的文件,它应该存在于另一个文件中,并创建一个命令序列来检查它是否存在。如果grep可以接受任意的多行模式,我会使用类似于 grep "`cat contentfile`" targetfile 与grep一样,我希望能够从命令中检查退出代码。我对输出不太感兴趣。事实上,从那时起,我就不需要通过管道连接到/dev/null,因此没有任何输出是首选的 我已经搜索了一些提示,但是找不到一

我试图使用公共bash命令grep、awk等检查文件中是否存在多行字符串

我希望有一个包含几行、普通行、而不是模式的文件,它应该存在于另一个文件中,并创建一个命令序列来检查它是否存在。如果grep可以接受任意的多行模式,我会使用类似于

grep "`cat contentfile`" targetfile
与grep一样,我希望能够从命令中检查退出代码。我对输出不太感兴趣。事实上,从那时起,我就不需要通过管道连接到/dev/null,因此没有任何输出是首选的

我已经搜索了一些提示,但是找不到一个能给出任何好点击率的搜索。有,但那是关于模式匹配的

我找到了pcre2grep,但需要使用标准*nix工具

例如:

内容文件:

line 3
line 4
line 5
目标文件:

line 1
line 2
line 3
line 4
line 5
line 6
这应该匹配并返回0,因为内容文件中的行序列在目标文件中的顺序完全相同

编辑:很抱歉,在这个问题的早期版本中,没有明确模式与字符串的比较以及输出与退出代码。

编辑:因为OP需要命令的结果,形式为真或假是或否,所以现在以这种方式编辑命令,并在GNU awk中创建和测试

请您尝试下面的方法,使用给定的样本进行测试,它应该打印模式文件中的所有连续行,如果它们以相同的顺序出现在目标文件中,则此代码中的连续行计数应该至少为2

awk '
FNR==NR{
  a[$0]
  next
}
($0 in a){
  if((FNR-1)==prev){
      b[++k]=$0
  }
  else{
      delete b
      k=""
  }
}
{
  prev=FNR
}
END{
  for(j=1;j<=k;j++){
      print b[j]
  }
}'  patternfile  targetfile
说明:在此处添加上述代码的说明

awk '                                     ##Starting awk program here.
FNR==NR{                                  ##FNR==NR will be TRUE when first Input_file is being read.
  a[$0]                                   ##Creating an array a with index $0.
  next                                    ##next will skip all further statements from here.
}
($0 in a){                                ##Statements from here will will be executed when 2nd Input_file is being read, checking if current line is present in array a.
  if((FNR-1)==prev){                      ##Checking condition if prev variable is equal to FNR-1 value then do following.
      b[++k]=$0                           ##Creating an array named b whose index is variable k whose value is increment by 1 each time it comes here.
  }
  else{                                   ##Mentioning else condition here.
      delete b                            ##Deleting array b here.
      k=""                                ##Nullifying k here.
  }
}
{
  prev=FNR                                ##Setting prev value as FNR value here.
}
END{                                      ##Starting END section of this awk program here.
  for(j=1;j<=k;j++){                      ##Starting a for loop here.
      print b[j]                          ##Printing value of array b whose index is variable j here.
  }
}'  patternfile  targetfile               ##mentioning Input_file names here.
编辑:由于OP需要命令的结果为真或假是或否,所以以这种方式编辑的命令现在在GNU awk中创建并测试

请您尝试下面的方法,使用给定的样本进行测试,它应该打印模式文件中的所有连续行,如果它们以相同的顺序出现在目标文件中,则此代码中的连续行计数应该至少为2

awk '
FNR==NR{
  a[$0]
  next
}
($0 in a){
  if((FNR-1)==prev){
      b[++k]=$0
  }
  else{
      delete b
      k=""
  }
}
{
  prev=FNR
}
END{
  for(j=1;j<=k;j++){
      print b[j]
  }
}'  patternfile  targetfile
说明:在此处添加上述代码的说明

awk '                                     ##Starting awk program here.
FNR==NR{                                  ##FNR==NR will be TRUE when first Input_file is being read.
  a[$0]                                   ##Creating an array a with index $0.
  next                                    ##next will skip all further statements from here.
}
($0 in a){                                ##Statements from here will will be executed when 2nd Input_file is being read, checking if current line is present in array a.
  if((FNR-1)==prev){                      ##Checking condition if prev variable is equal to FNR-1 value then do following.
      b[++k]=$0                           ##Creating an array named b whose index is variable k whose value is increment by 1 each time it comes here.
  }
  else{                                   ##Mentioning else condition here.
      delete b                            ##Deleting array b here.
      k=""                                ##Nullifying k here.
  }
}
{
  prev=FNR                                ##Setting prev value as FNR value here.
}
END{                                      ##Starting END section of this awk program here.
  for(j=1;j<=k;j++){                      ##Starting a for loop here.
      print b[j]                          ##Printing value of array b whose index is variable j here.
  }
}'  patternfile  targetfile               ##mentioning Input_file names here.
一行:

$ if [ $(diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1 | wc -l) == $(cat patternfile | wc -l) ]; then echo "ok"; else echo "error"; fi 
说明:

首先是使用diff比较两个文件:

然后过滤以仅显示感兴趣的行,即匹配之前和之后的行,再加上额外的1行,以检查patternfile中的行是否不间断地匹配

diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 

                                      > line 2
line 3                                (
line 4                                (
line 5                                (
                                      > line 6  
然后省略第一行和最后一行:

diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1

line 3                                (
line 4                                (
line 5                                (
添加一些代码以检查行数是否与patternfile中的行数匹配:

要将其与返回代码一起使用,可以创建如下脚本:

#!/bin/bash
patternfile=$1                                                                                                          
targetfile=$2
if [ $(diff --left-column -y $patternfile $targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1 | grep '(' | wc -l) == $(cat $patternfile | wc -l) ]; 
then 
   exit 0; 
else 
   exit 1; 
fi
上述脚本命名为comparepatterns时的测试:

一行:

$ if [ $(diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1 | wc -l) == $(cat patternfile | wc -l) ]; then echo "ok"; else echo "error"; fi 
说明:

首先是使用diff比较两个文件:

然后过滤以仅显示感兴趣的行,即匹配之前和之后的行,再加上额外的1行,以检查patternfile中的行是否不间断地匹配

diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 

                                      > line 2
line 3                                (
line 4                                (
line 5                                (
                                      > line 6  
然后省略第一行和最后一行:

diff --left-column -y patternfile targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1

line 3                                (
line 4                                (
line 5                                (
添加一些代码以检查行数是否与patternfile中的行数匹配:

要将其与返回代码一起使用,可以创建如下脚本:

#!/bin/bash
patternfile=$1                                                                                                          
targetfile=$2
if [ $(diff --left-column -y $patternfile $targetfile | grep '(' -A1 -B1 | tail -n +2 | head -n -1 | grep '(' | wc -l) == $(cat $patternfile | wc -l) ]; 
then 
   exit 0; 
else 
   exit 1; 
fi
上述脚本命名为comparepatterns时的测试:


awk中的另一个解决方案:

echo $(awk 'FNR==NR{ a[$0]; next}{ x=($0 in a)?x+1:0 }x==length(a){ print "OK" }' patternfile targetfile ) 

如果存在匹配项,则返回OK。

awk中的另一个解决方案:

echo $(awk 'FNR==NR{ a[$0]; next}{ x=($0 in a)?x+1:0 }x==length(a){ print "OK" }' patternfile targetfile ) 

如果存在匹配项,则返回OK。

最简单的方法是使用滑动窗口。首先读取模式文件,然后是要搜索的文件

(FNR==NR) { a[FNR]=$0; n=FNR; next }
{ b[FNR]=$0 }
(FNR >= n) { for(i=1; i<=n;++i) if (a[i] != b[FNR-n+i]) { delete b[FNR-n+1]; next}}
{ print "match at", FNR-n+1}
{ r=1}
END{ exit !r}

最简单的方法是使用滑动窗口。首先读取模式文件,然后是要搜索的文件

(FNR==NR) { a[FNR]=$0; n=FNR; next }
{ b[FNR]=$0 }
(FNR >= n) { for(i=1; i<=n;++i) if (a[i] != b[FNR-n+i]) { delete b[FNR-n+1]; next}}
{ print "match at", FNR-n+1}
{ r=1}
END{ exit !r}

您没有说是否需要regexp匹配或字符串匹配,我们无法确定,因为您将搜索文件命名为patternfile,并且模式可能意味着任何东西,在某一点上,您暗示您希望执行字符串匹配检查,以确定是否存在多行字符串,但随后您使用的是grep和pcregpre,没有为string而不是regexp指定参数火柴

在任何情况下,它们都可以使用任何awk(包括POSIX标准awk)执行任何您想要的操作,并且您说过希望在每个UNIX设备上的任何shell中使用标准UNIX工具:

对于regexp匹配:

$ cat tst.awk
NR==FNR { pat = pat $0 ORS; next }
{ tgt = tgt $0 ORS }
END {
    while ( match(tgt,pat) ) {
        printf "%s", substr(tgt,RSTART,RLENGTH)
        tgt = substr(tgt,RSTART+RLENGTH)
    }
}

$ awk -f tst.awk patternfile targetfile
line 3
line 4
line 5
对于字符串匹配:

$ cat tst.awk
NR==FNR { pat = pat $0 ORS; next }
{ tgt = tgt $0 ORS }
END {
    lgth = length(pat)
    while ( beg = index(tgt,pat) ) {
        printf "%s", substr(tgt,beg,lgth)
        tgt = substr(tgt,beg+lgth)
    }
}

$ awk -f tst.awk patternfile targetfile
line 3
line 4
line 5
话虽如此,如果您对模式文件内容的regexp匹配和反斜杠解释没有异议,那么使用GNU awk可以执行以下操作,\t被视为文字选项卡:

$ awk -v RS="$(cat patternfile)" 'RT!=""{print RT}' targetfile
line 3
line 4
line 5
或使用GNU grep:

$ grep -zo "$(cat patternfile)" targetfile | tr '\0' '\n'
line 3
line 4
line 5

根据您真正尝试进行的匹配类型以及可用的工具版本,还有许多其他选项。

您没有说明是否需要regexp匹配或字符串匹配,我们无法确定,因为您将搜索文件命名为patternfile,模式可能意味着任何事情,并且在某一点上您暗示要进行字符串匹配匹配检查是否存在多行字符串,但您使用的是grep和pcregpre,没有为字符串指定参数,而不是regexp匹配

在任何情况下,它们都可以使用任何awk(包括POSIX标准awk)执行任何您想要的操作,并且您说过要使用标准UNIX工具 在每个UNIX机箱上的任何shell中:

对于regexp匹配:

$ cat tst.awk
NR==FNR { pat = pat $0 ORS; next }
{ tgt = tgt $0 ORS }
END {
    while ( match(tgt,pat) ) {
        printf "%s", substr(tgt,RSTART,RLENGTH)
        tgt = substr(tgt,RSTART+RLENGTH)
    }
}

$ awk -f tst.awk patternfile targetfile
line 3
line 4
line 5
对于字符串匹配:

$ cat tst.awk
NR==FNR { pat = pat $0 ORS; next }
{ tgt = tgt $0 ORS }
END {
    lgth = length(pat)
    while ( beg = index(tgt,pat) ) {
        printf "%s", substr(tgt,beg,lgth)
        tgt = substr(tgt,beg+lgth)
    }
}

$ awk -f tst.awk patternfile targetfile
line 3
line 4
line 5
话虽如此,如果您对模式文件内容的regexp匹配和反斜杠解释没有异议,那么使用GNU awk可以执行以下操作,\t被视为文字选项卡:

$ awk -v RS="$(cat patternfile)" 'RT!=""{print RT}' targetfile
line 3
line 4
line 5
或使用GNU grep:

$ grep -zo "$(cat patternfile)" targetfile | tr '\0' '\n'
line 3
line 4
line 5

还有许多其他选项,这取决于您真正想要进行的匹配类型以及可用的工具版本。

下面的Python one liner说明了这一点

python -c "content=open('content').read(); target=open('target').read(); exit(0 if content in target else 1);"

根据who的一条评论,下面的pythonner实现了这一点

python -c "content=open('content').read(); target=open('target').read(); exit(0 if content in target else 1);"


你在Linux上吗?或者您需要MacOS/BSD兼容性吗?perl-0777-pe“如果s/”$cat patternfile/,则退出0”;退出1‘targetfile?@Cyrus有效,至少对于我刚刚做的一些简单测试是有效的。请把它转换成答案。如果patternfile包含/,它就不起作用。我相信还有更好的解决方案。这可能会有帮助:你在Linux上吗?或者您需要MacOS/BSD兼容性吗?perl-0777-pe“如果s/”$cat patternfile/,则退出0”;退出1‘targetfile?@Cyrus有效,至少对于我刚刚做的一些简单测试是有效的。请把它转换成答案。如果patternfile包含/,它就不起作用。我相信还有更好的解决方案。这可能会有帮助:如果你能解释这个解决方案是如何工作的,那就太棒了。@codeforester,现在已经用解决方案添加了解释,干杯。当将patternfile的最后一行更改为第6行时,这个脚本将输出第3行;第4行;第6行。哪个不是期望的输出?@Luuk,我相信IMHO哪个应该是期望的输出,因为所有都是以相同的顺序出现的,OP可以确认。当没有匹配时,您的awk语句的返回码仍然是0或OK。通常,可以/应该通过echo$检查返回代码?在语句之后,仅返回“是”是不够的。我的一行有同样的问题,我会编辑这一刻。。。如果你能解释这个解决方案是如何工作的,那就太棒了。@codeforester,现在已经用解决方案添加了解释,干杯。当将patternfile的最后一行更改为第6行时,这个脚本将输出第3行;第4行;第6行。哪个不是期望的输出?@Luuk,我相信IMHO哪个应该是期望的输出,因为所有都是以相同的顺序出现的,OP可以确认。当没有匹配时,您的awk语句的返回码仍然是0或OK。通常,可以/应该通过echo$检查返回代码?在语句之后,仅返回“是”是不够的。我的一行有同样的问题,我会编辑这一刻。。。无论匹配的是什么,您的两个建议都返回退出状态0。我需要能够在bash/makefile中检查结果。这是正确的。当然,您应该在问题中说明这一点,但这是一个非常小的改动-如果您在实现这一点时遇到任何问题,请告诉我,如果您确实需要帮助,请确保编辑您的问题以包含所有相关信息,包括如果您尝试进行字符串或regexp匹配,打印到stdout/stderr的内容、退出状态等。必须指出的是,如果您有EByte日期文件,第一个案例将失败。非常好的RS解决方案。无论匹配情况如何,您的两个建议都返回退出状态0。我需要能够在bash/makefile中检查结果。这是正确的。当然,您应该在问题中说明这一点,但这是一个非常小的改动-如果您在实现这一点时遇到任何问题,请告诉我,如果您确实需要帮助,请确保编辑您的问题以包含所有相关信息,包括如果您尝试进行字符串或regexp匹配,打印到stdout/stderr的内容、退出状态等。必须指出的是,如果您有EByte日期文件,第一个案例将失败。非常好的RS解决方案。