使用 sed、awk 或 grep 进行多行模式匹配

28 grep sed awk text-processing

是否可以使用sed,awk或进行多行模式匹配grep?举个例子,我想得到{和之间的所有线}

所以它应该能够匹配

 1. {}
 2. {.....}
 3. {.....
.....}
Run Code Online (Sandbox Code Playgroud)

最初将问题用作<p>示例。编辑了问题以使用{和}。

she*_*ter 22

虽然我同意上面的建议,除了微小的或完全是临时的之外,您还需要一个解析器,但(几乎;-)可以将大括号之间的多行块与 sed 匹配。

这是 sed 代码的调试版本

sed -n '/[{]/,/[}]/{
    p
    /[}]/a\
     end of block matching brace

    }' *.txt
Run Code Online (Sandbox Code Playgroud)

一些笔记,

  • -n 表示“没有处理过的默认打印行”。
  • 'p' 表示现在打印该行。
  • 该构造/[{]/,/[}]/是一个范围表达式。这意味着扫描直到找到与第一个模式匹配的内容(/[{]/)然后扫描直到找到第二个模式(/[}]/)然后执行您在 sed 代码中的 { } 之间找到的任何操作。在这种情况下,'p' 和调试代码。(这里没有解释,使用它,修改它或将其取出最适合你)。

当您满意地证明代码确实匹配由 {,} 分隔的块时,您可以删除块调试的 /[}]/a\ 结尾。

此代码示例将跳过不在花括号对内的任何内容。正如上面其他人所指出的,如果您在字符串、reg-exps 等中嵌入了任何额外的 {,},或者在右大括号是同一行的情况下,它会很容易混淆,(感谢 fred.bear)

我希望这有帮助。


Coo*_*per 14

您可以对 pcregrep 使用 -M(多行)选项:

pcregrep -M '\{(\s*.*\s*)*\}' test.txt
Run Code Online (Sandbox Code Playgroud)

\s 是空格(包括换行符),因此它匹配零次或多次出现的(空格后跟 .* 后跟空格),全部用大括号括起来。

更新:

这应该进行非贪婪匹配:

pcregrep -n -M '\{(\n*.*?\n*)*?\}' test.txt
Run Code Online (Sandbox Code Playgroud)


Mar*_*cin 6

类似 XML 的表达式(无限递归标记)不是“常规语言”,因此无法使用正则表达式(regex)进行解析。原因如下:

/sf/ask/121264391/

http://www.perlmonks.org/?node_id=668353

/sf/ask/96566711/


dub*_*jim 5

解析器.awk:

#!/usr/bin/awk -f    
function die(msg) { print msg > "/dev/stderr"; exit 1 }
BEGIN {
  FS=opener
  if (mode=="l") linewise=1
  else if (mode=="i") trim_closer=length(closer)
  else if (mode!="a") die("mode must be one of: l,i,a")
}
{
  live=level
  for (f=1; f<=NF; f++) {
    if (f>1) {
      live=++level
      if (mode=="i" && level>1 || mode=="a") printf "%s", opener
    }
    cur=$f
    level-=gsub(closer, "", cur)
    if (level<0) die("Unbalanced")
    if (!linewise) {
      cur=$f
      if (sub(".*" closer, "", cur)) printf "%s", 
        substr($f, 1, length($f) - length(cur) - (level ? 0 : trim_closer))
      else if (live) printf "%s", $f
    }
  }
  if (live) {
    if (linewise) print
    else print ""
  }
}
END { if (level>0) die("Unbalanced") }
Run Code Online (Sandbox Code Playgroud)

调用为awk -v'opener={' -v'closer=}' -v'mode=a' -f parser.awk。如果 mode 是a,它打印所有最外面的,平衡的括号和内容{...};如果 mode 是i,它只打印它们的内容;如果 mode 是l,它会打印最外层{...}开始、保持打开或关闭的完整行。