替換匹配模式中的第 n 行

替換匹配模式中的第 n 行

我有以下文字檔。

banana
apple
juice
mango
something

我正在搜尋模式juice,並且我想以相反的順序找到該匹配模式的第二行(即匹配模式上方的兩行)並將其替換為coconut

預期輸出:

coconut
apple
juice
mango
something

我嘗試了以下操作,但它只是刪除了上面的兩行,而不是我正在尋找的確切行。

tac foo.txt |sed '/juice/I,+2 d' |tac
mango
something

我認為調整上面的腳本可以完成這項工作,但我不確定。

注意:匹配不會重複出現,並且不需要是精確匹配(也就是說,也可以在長行中找到匹配)。匹配應區分大小寫。

答案1

如果ed可以的話,你需要編輯一個文件,而不是一個流,並且只有一個 juice

$ more <<-EOF | ed -s ./tmp.txt
	/juice/
	-2
	c
	coconut
	.
	w
	q
EOF
$

找到那條線,走兩行,change, write,然後 quit。


@d-ben-knoble 在評論中建議的更緊湊的變體:

$ printf '%s\n' '/^juice$/-2s/.*/coconut/' w q | ed -s ./tmp.txt

答案2

按照你的做法,

tac file|sed '/juice/{n;n;s/.*/coconut/}'|tac
  • /juice/與 匹配一行juice
  • n;n;列印目前行和下一行。
  • s/.*/coconut/進行替換。

顯然你有GNU sed,所以你也可以使用-z將整個文件放入內存並直接編輯上面的第二行juice,

sed -rz 's/[^\n]*(\n[^\n]*\n[^\n]*juice)/coconut\1/' file

[^\n]表示“不是換行符”,括號捕獲由反向引用()複製的群組。\1

答案3

$ tac file | awk 'c&&!(--c){$0="coconut"} /juice/{c=2} 1' | tac
coconut
apple
juice
mango
something

答案4

這是另一種awk方法,這次是雙遍方法:

awk 'NR==FNR&&/juice/{m=FNR} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file
  • 我們指定文件兩次作為命令列參數,以便它被處理兩次。
  • 在第一遍中(其中FNR,每個文件行計數器,等於NR全域行計數器),我們只需識別搜尋模式juice出現在哪一行,並將其儲存在變數 中m
  • 在第二遍中,我們將行號設定m-2為替換文字coconut
  • 作為一般規則,我們列印包含任何修改的行,但僅在第二遍中(其中條件NR>FNR評估為“true”)。

如果您有 GNU awk(其他一些awk實作也支持這一點),您可以使用以下命令在找到匹配項後立即中止第一遍,從而加快流程nextfile

awk 'NR==FNR&&/juice/{m=FNR;nextfile} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file

相關內容