在命令行匹配多行字符串:如果模式匹配则返回某行,否则返回空字符串

时间:2014-05-08 13:22:50

标签: regex unix command-line pcre pcregrep

我所获得的命令的输出在“成功”时采用以下形式:

/ >  -------
ABC123
/ > 

此命令可能会发出类似这样的内容(“失败”):

/ >  -------
ABC123
 -------
DEF456
 -------
Hello (world!)
 -------
(any old string, really)
/ > 

或者,这(另一个“失败”):

/ > / >

对于第一个例子,我想发出:

ABC123

对于其他两个例子,我想发出空字符串。

我试过这个,这对于第三个例子非常有用:

mycmd | pcregrep -M '(?:/\s>\s{2}-{7}\n)[^\n]*(?!\n.*\n)'

但是对于它发出的前两个例子:

/ >  -------
ABC123

我不知道该怎么做。我的上面的正则表达式是尝试匹配前导/ > -------但不捕获它,然后匹配下一行只有当它没有跟着另一行以换行符结尾时。我可以使用pcregrep之外的其他内容来解决此问题,但我无法使用awksed来表达此问题。我会使用Python,但它对我的需求来说太慢了。有什么帮助吗?

3 个答案:

答案 0 :(得分:1)

您还可以使用awk:

BEGIN {
   first_line = "";
   second_line = "";
   third_line = "";

   ctr = 0;
}
{
   if (ctr == 0 ){
      first_line = $0;
   } else if (ctr == 1) {
      second_line = $0;
   } else if (ctr == 2 ) {
      third_line = $0;
   }
   ctr++;
}
END {
   if( first_line ~ /\/ >  -------/){
      if( third_line ~ /\/ >/){
         print second_line;
      }
   }
}

输出:

$ echo "/ >  -------\nABC12\n ---\n/ >\n" | awk -f test.awk
$ echo "/ >  -------\nABC12\n/ >\n" | awk -f test.awk
ABC12
$

我确信awk专家会畏缩,但很快就完成了工作。

答案 1 :(得分:1)

我认为以下内容可行,但如果它包含换行符,我无法使用后视表达式。

mycmd | pcregrep -M '(?<=^/ >  -{7}\n).*\n(?=/ > $)'

但以下两阶段解决方案对我有用:

mycmd | pcregrep -M '^/ >  -{7}\n.*\n/ > $' | pcregrep -v '^/ >'

根据OP的回答进行更新

我喜欢\ K逃脱: - )

我认为您 想要符合以下情况

/ > -------
/ > perhaps text here
/ > 

当它包含\ n时,我能够得到负面的工作,即使它嵌入在正向前看中也是如此。

这是一个更简单的正则表达式,\K更接近你想要的。它不允许/ >之后的任何内容,但它仍然允许/ > -------之前的行。

mycmd | pcregrep -Mo '^/ >  -{7}\n\K(?!/ >).+(?=\n/ > $(?!\n[\s\S]))'

如果允许捕获的行以/ >开头,则更简单:

mycmd | pcregrep -Mo '^/ >  -{7}\n\K.+(?=\n/ > $(?!\n[\s\S]))'

最终更新

这是一个sed one liner,我相信会给出确切的结果,不允许任何额外的行在之前或之后。但是,它确实允许捕获以/ >开头的行。

mycmd | sed -n '1{/^\/ >  -\{7\}$/{n;/./{h;n;/^\/ > $/{${x;p}}}}}'

这是另一种sed解决方案

mycmd | sed -n '1{h;n;H;x;N;${/^\/ >  -\{7\}\n..*\n\/ > $/{x;p}}}'

答案 2 :(得分:1)

我实际上通过以下pcregrep命令获得了成功(在咬牙切齿之后):

pcregrep -Mo '^/ > {2}-{7}[\n\r]\K[^\n\r]+(?=[\n\r]/ > $)'

没有-o标志,它包含第一行(尽管使用\K)。 -o使pcregrep仅发出与模式匹配的行。事实证明,在尝试匹配换行符时,负面预测似乎不适用于多行模式。此外,在多线模式下,\s将匹配换行符,因此我停止使用它。

我确实想要注意,这个解决方案和dbenham的解决方案都不是我想要的。我希望在第二行之后检查除了最后一行(即不包含另一个换行符)之外没有任何其他行。这些解决方案更多地假设输出结束,但必须这样做。