一致するパターンのn行目を置き換えます。

一致するパターンのn行目を置き換えます。

次のテキストファイルがあります。

banana
apple
juice
mango
something

パターンを検索していますが、一致juiceするパターンの2行目(つまり、一致するパターンの上の2行)を逆の順序で検索して置き換えようとしていますcoconut

予想出力:

coconut
apple
juice
mango
something

私は次のことを試しましたが、上記の2行だけが削除され、私が探していた行は削除されませんでした。

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
$

その行を見つけて2行に移動し、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を使用し、上記の2行目を直接編集することもできます。

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
  • 私たちはファイルを指定します二重2回処理されるようにコマンドライン引数として使用します。
  • 最初のパス(FNRファイルごとのラインカウンタがNRグローバルラインカウンタと同じです)では、juice検索パターンが発生するラインを簡単に識別して変数に保存しますm
  • 2番目のパスでは、行番号をm-2代替テキストに設定しますcoconut
  • 通常、修正を含む行を印刷しますが、2番目のステップ(条件が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

関連情報