
我有一個日誌文件,其中包含重複特徵的清單。例如:
## This is the pattern of lines
time
urgency
icon_path
summary
body
appname
## Below is what the log file would actually look like
12:30
critical
test notification
notification
notify-send
11:00
low
earlier notification
notification
notify-send
10:46
normal
hello
world
dunstify
我正在嘗試找到一種方法來搜尋與我的搜尋字詞相符的行塊/簇,然後在 bash 中刪除它們。正如您在上面的範例中看到的,有時行是空的,有時是填充的。到目前為止我發現的最好的“解決方案”是使用sed '/12:30/,+5 d'
或稍微好一點sed '/12:30/,/notify-send/d'
。這兩個方法的問題在於,第一個方法將刪除所有出現的時間戳,從而刪除多個日誌條目;另一個命令的問題是,如果有兩個或多個條目具有相同的時間和應用程式名稱,則所有符合的條目都將被刪除。
我一直在努力工作但一直失敗的事情是做類似的事情:sed '/12:30\n^.*$\n^.*$\ntest notification\nnotification\nnotify-send/d' /tmp/notification_log
。請注意,第二行和第三行可以是任何內容(分別是 Urgency 和 icon_path 行),這就是我使用的原因^.*$
(坦白說,我甚至不確定這是否是正確的正規表示式)。
編輯:使用上面失敗的命令,我希望輸出為:
11:00
low
earlier notification
notification
notify-send
10:46
normal
hello
world
dunstify
此命令的輸入為:
12:30
*anything*
*anything*
test notification
notification
notify-send
答案1
實際上並不難,只要所有簇都是 M 行長,M 是固定的,簇不重疊,我們不需要搜尋任何簇的開頭。在我們的例子中,M 是 6。
sed
允許您匹配多行,但由於它通常一次處理一行,因此您需要明確地將其他行附加到模式空間。你這樣做N
:
sed 'N;N;N;N;N; /12:30\n.*\n.*\ntest notification\nnotification\nnotify-send/d'
^
剩下的就是沒有和錨點的程式碼$
。錨點通常分別與「行的開頭」和「行的結尾」相關聯;但sed
它們確實是「…弦」。當sed
一次處理一行時沒有差別。在我們的例子中,我們絕對應該記住錨點是“......字串”。把它們放在中間是沒有意義的。並不是他們永遠不會匹配任何東西。sed
首先不會將它們解釋為錨點,它會將它們解釋為文字^
和$
。
字串中間不需要「... of the line」錨點。除最後一行外的任何行都在某個換行符之前結束;任何行,但首先在某個換行符之後開始。所以匹配就夠了\n
。
也許您嘗試使用錨點來確保.*
(這是貪婪的並且可以匹配換行符)不匹配超過一行。就算當^
了$
「…一線」主播,.*
也會貪心。考慮一下: 中的模式空間sed
在最後一行*之後從不包含換行符號。在我們的例子中,我們知道模式空間最多有六行;我們\n
一共使用了五次。這保證了正規表示式的每個片段只能匹配簇中的特定行。
錨仍然可以提供幫助。上述指令可以刪除以notify-send-whatever
.結尾的群集。$
是防止這種情況的正確方法。除了12:30
比賽之外沒有其他時間12:30
;但它不同2:30
,所以一般來說^
也很有用。改進後的命令:
sed 'N;N;N;N;N; /^12:30\n.*\n.*\ntest notification\nnotification\nnotify-send$/d'
* 這並不意味著模式空間的末端永遠不可能有換行符。末尾的換行符表示該字元後面有一行。這是最後一行,而且是空的。且後面沒有換行符,因此「最後一行後沒有換行符」成立。