Text-Processing

如何從文件中獲取兩個模式之間最後一次出現的行?

  • July 3, 2021

我有一個報告程序輸出的日誌文件,我想從兩個模式的最後一次出現之間提取所有行。

圖案將沿線;

Summary process started at <datestring>

Summary process finished at <datestring> with return code <num>

整個文件中將有幾個這些模式的實例,以及許多其他資訊。我想列印唯一的最後一次出現。

我知道我可以使用:

sed -n '/StartPattern/,/EndPattern/p' FileName

獲取模式之間的線條,但不確定如何獲取最後一個實例。Sed 或 awk 解決方案會很好。

編輯: 在檢測到 StartPattern 之後,當多個 StartPattern 出現而沒有 EndPattern,或者在文件結尾之前沒有 EndPattern 時,我完全不清楚我想要的行為

對於缺少 EndPattern 的多個 StartPattern,我只想要從最後一個 StartPattern 到 EndPattern 的行。

對於在沒有 EndPattern 的情況下到達 EOF 的 StartPattern,我希望所有內容都達到 EOF,然後輸入一個字元串以警告已到達 EOF。

你總是可以這樣做:

tac < fileName | sed  '/EndPattern/,$!d;/StartPattern/q' | tac

如果您的系統沒有 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

但這意味著讀取整個文件。

請注意,如果StartPattern在 aStartPattern和下一個之間有另一個,EndPattern或者如果最後一個StartPattern沒有結尾EndPattern,或者如果有行匹配兩個StartPatternand ,它可能會給出不同的結果EndPattern

awk '
 /StartPattern/ {
   inside = 1
   text = ""
 }
 inside {text = text $0 RS}
 /EndPattern/ {inside = 0} 
 END {printf "%s", text}' < filename

會使它的行為更像這種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

為避免讀取整個文件:

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}'

可移植性說明:對於/dev/stderr,您需要具有此類特殊文件的系統(請注意,在 Linux 上,如果 stderr 在可搜尋文件上打開,該文件將在文件開頭而不是文件中的目前位置寫入文本)或awk模擬它的實現gawkmawk或busybox awk(那些解決上述Linux問題的方法)。

在其他系統上,您可以替換print ... > "/dev/stderr"print ... | "cat>&2".

引用自:https://unix.stackexchange.com/questions/289642