[英]sed: How to match these 4 consecutive lines with RegEx for deleting?
我有一個包含這些行的文件,以及由於更新而被文件重置的可能性(不在我的控件中),我需要使用sed
或類似方法來匹配這些行,並在執行該命令的Bash腳本的末尾刪除它們更新過程。 只要有效,不一定必須是RegEx,但是RegEx是我知道的唯一方法,而且我可能永遠不會學習替代方法的新語法:
if cvars.Number("sv_alltalk", 0) > 0 then
ErrorNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\n")
RunConsoleCommand("sv_alltalk", "0")
end
我認為最好將這些行的開頭和結尾進行匹配,以防開發人員搞砸了,包括縮進的更改。 這些行不會重復,因此可以匹配刪除第一個匹配項。
我的RegEx嘗試不起作用,沒有匹配項:
1:{
'^(\t| )+if cvars\.Number\("sv_alltalk", 0\) > 0 then\r\n(\t| )+ErrorNoHalt\("TTT WARNING: sv_alltalk is enabled\. Dead players will be able to talk to living players\. TTT will now attempt to set sv_alltalk 0\.\\n"\)\r\n(\t| )+RunConsoleCommand\("sv_alltalk", "0"\)\r\n(\t| )+end.+$'
} 2:{
'(\t| )+if cvars\.Number\("sv_alltalk", 0\) > 0 then\r\n(\t| )+ErrorNoHalt\("TTT WARNING: sv_alltalk is enabled\. Dead players will be able to talk to living players\. TTT will now attempt to set sv_alltalk 0\.\\n"\)\r\n(\t| )+RunConsoleCommand\("sv_alltalk", "0"\)\r\n(\t| )+end.+'
} 3:{
'(\t| )+if cvars\.Number\("sv_alltalk", 0\) > 0 then\r(\t| )+ErrorNoHalt\("TTT WARNING: sv_alltalk is enabled\. Dead players will be able to talk to living players\. TTT will now attempt to set sv_alltalk 0\.\\n"\)\r(\t| )+RunConsoleCommand\("sv_alltalk", "0"\)\r(\t| )+end.+'
} 4:{
'(\t| )+if cvars\.Number\("sv_alltalk", 0\) > 0 then\n(\t| )+ErrorNoHalt\("TTT WARNING: sv_alltalk is enabled\. Dead players will be able to talk to living players\. TTT will now attempt to set sv_alltalk 0\.\\n"\)\n(\t| )+RunConsoleCommand\("sv_alltalk", "0"\)\n(\t| )+end.+'
}
只要文件可以裝入內存,一種(相當)簡單的方法就可以在sed中進行多行匹配:
sed -n '1h; 1!H; $ { x; s/pattern/replacement/; p }' filename
這會將整個文件讀到保持緩沖區中,並在包含所有內容后將其交換回模式空間,進行替換然后打印。 因此,您可以這樣做:
sed -n '1h; 1!H; $ { x; s/[\t ]*if cvars\.Number("sv_alltalk", 0) > 0 then\s*\n\s*ErrorNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\\n")\s*\n\s*RunConsoleCommand("sv_alltalk", "0")\s*\n\s*end//; p }' filename
當然,這是非常長和丑陋的。 根據唯一識別匹配所需的模式數量,其他方法可能(但不一定是)更合適。 例如,如果第一行和最后一行足以找到沒有誤報的匹配項,則可以使用模式范圍來定義部分,然后按照基本形式排除該部分
sed -n '/begin-pattern/,/end-pattern/ ! p'
/begin-pattern/,/end-pattern/
選擇范圍!
反轉它, p
是打印命令,即,打印不在該范圍內的每一行。 在您的情況下,可能看起來像這樣:
sed -n '/^\s*if cvars\.Number("sv_alltalk", 0) > 0 then\s*$/,/^\s*end\s*$/ !p' filename
請注意, if
s , 則不會嵌套 。 特別是,如果塊中還有另一end
,它將中斷,因此只有在模式的第一行唯一標識匹配項且模式僅包含最后一行的情況下,此方法才起作用。 與第一種方法相比,它的好處是sed可以在單獨的行上工作,而不必將整個文件放入內存中。 盡管我會驚訝地看到一個源代碼文件足夠大,足以使任何人擔心此特定問題。
或者,如果您知道在唯一標識第一行之后必須刪除特定的數字行(在這種情況下可能不是最好的方法),而第一行足以標識匹配項,
sed '/begin-pattern/ { N;N;N;d }' filename
( N
的數量定義了要丟棄的行數)也可以工作。 我之所以僅提及這一點,是因為標題可能會引誘某人遇到類似的問題。 我認為這不是解決您的特定問題的明智方法。
sed腳本
sed -i.bak '
/^[[:space:]]*if cvars.Number("sv_alltalk", 0) > 0 then *$/,/^[[:space:]]*end *$/{
/^[[:space:]]*end *$/!{H;d}
/^[[:space:]]*end *$/{H;g;s/.*//g;x
/^[[:space:]]*if cvars.Number("sv_alltalk", 0) > 0 then *\n *\ErrorNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\\n") *\n *RunConsoleCommand("sv_alltalk", "0") *\n *end */d}
}' $1
在文件中調用腳本的位置
倒數第二行是您放置“ if block”的地方
/ *if cvars.Number("sv_alltalk", 0) > 0 then *\n *\ErrorNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\\n") *\n *RunConsoleCommand("sv_alltalk", "0") *\n *end */
筆記:
1.每行以空格開頭,后跟*
並在每行各行末尾的換行符之前。 這是為了便於匹配每行前后的任何空格。
2.您的腳本中有“ \\n
”。 這是一個特殊字符,因此我使用\\\\n
來轉義反斜杠字符。
測試樣本
if cvars.Number("sv_alltalk", 0) > 0 then
ErrorNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\n")
RunConsoleCommand("sv_alltalk", "0")
end
if cvars.Number("sv_alltalk", 0) > 0 then
Erro7676rNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\n")
RunConsoleCommand("sv_alltalk", "0")
end
注意:在第二個if塊中,有Erro7676rNoHalt
而不是ErrorNoHalt
,因此不應刪除此if塊,因為我們完全匹配整個if塊。
此樣本的輸出
if cvars.Number("sv_alltalk", 0) > 0 then
Erro7676rNoHalt("TTT WARNING: sv_alltalk is enabled. Dead players will be able to talk to living players. TTT will now attempt to set sv_alltalk 0.\n")
RunConsoleCommand("sv_alltalk", "0")
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.