如何从文件中获取两个模式之间最后一次出现的行?

Arr*_*cal 2 sed awk text-processing gawk

我有一个报告进程输出的日志文件,我想从两个模式的最后一次出现之间提取所有行。

图案将沿线;

Summary process started at <datestring>
Run Code Online (Sandbox Code Playgroud)

Summary process finished at <datestring> with return code <num>
Run Code Online (Sandbox Code Playgroud)

整个文件中将有这些模式的几个实例,以及许多其他信息。我想打印唯一的最后一次出现。

我知道我可以使用:

sed -n '/StartPattern/,/EndPattern/p' FileName
Run Code Online (Sandbox Code Playgroud)

获取模式之间的线条,但不确定如何获取最后一个实例。sed 或 awk 解决方案就可以了。

编辑: 在检测到 StartPattern 后,当多个 StartPattern 出现而没有 EndPattern 时,或者文件末尾之前没有 EndPattern 时,我完全不清楚我想要的行为

对于缺少 EndPattern 的多个 StartPattern,我只想要从最后一个 StartPattern 到 EndPattern 的行。

对于在没有 EndPattern 的情况下到达 EOF 的 StartPattern,我希望一切都达到 EOF,然后输入一个字符串来警告到达 EOF。

Sté*_*las 6

你总是可以这样做:

tac < fileName | sed  '/EndPattern/,$!d;/StartPattern/q' | tac
Run Code Online (Sandbox Code Playgroud)

如果您的系统没有 GNU tac,您也许可以使用它tail -r

你也可以这样做:

awk '
  inside {
    text = text $0 RS
    if (/EndPattern/) inside=0
    next
  }
  /StartPattern/ {
    inside = 1
    text = $0 RS
  }
  END {printf "%s", text}' < filename
Run Code Online (Sandbox Code Playgroud)

但这意味着读取整个文件。

请注意,如果StartPatternaStartPattern和下一个之间有另一个,EndPattern或者如果最后一个StartPattern没有结尾,EndPattern或者如果有与StartPattern和匹配的行,它可能会给出不同的结果EndPattern

awk '
  /StartPattern/ {
    inside = 1
    text = ""
  }
  inside {text = text $0 RS}
  /EndPattern/ {inside = 0} 
  END {printf "%s", text}' < filename
Run Code Online (Sandbox Code Playgroud)

会使它的行为更像该tac+sed+tac方法(未关闭的尾随StartPattern情况除外)。

最后一个似乎最接近您编辑的要求。添加警告只是:

awk '
  /StartPattern/ {
    inside = 1
    text = ""
  }
  inside {text = text $0 RS}
  /EndPattern/ {inside = 0} 
  END {
    printf "%s", text
    if (inside)
      print "Warning: EOF reached without seeing the end pattern" > "/dev/stderr"
  }' < filename
Run Code Online (Sandbox Code Playgroud)

To avoid reading the whole file:

tac < filename | awk '
  /StartPattern/ {
    printf "%s", $0 RS text
    if (!inside)
      print "Warning: EOF reached without seeing the end pattern" > "/dev/stderr"
    exit
  }
  /EndPattern/ {inside = 1; text = ""}
  {text = $0 RS text}'
Run Code Online (Sandbox Code Playgroud)

Portability note: for /dev/stderr, you need either a system with such a special file (beware that on Linux if stderr is open on a seekable file that will write the text at the beginning of the file instead of the current position within the file) or an awk implementation that emulates it like gawk, mawk or busybox awk (those work around the Linux issue mentioned above).

On other systems, you can replace print ... > "/dev/stderr" with print ... | "cat>&2".