如何從文件中獲取兩個模式之間最後一次出現的行?
我有一個報告程序輸出的日誌文件,我想從兩個模式的最後一次出現之間提取所有行。
圖案將沿線;
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
,或者如果有行匹配兩個StartPattern
and ,它可能會給出不同的結果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
模擬它的實現gawk
,mawk
或busyboxawk
(那些解決上述Linux問題的方法)。在其他系統上,您可以替換
print ... > "/dev/stderr"
為print ... | "cat>&2"
.