
Ich habe folgende Textdatei.
banana
apple
juice
mango
something
Ich suche nach dem Muster juice
und möchte die zweite Zeile dieses passenden Musters in umgekehrter Reihenfolge finden (also 2 Zeilen über dem passenden Muster) und durch ersetzen coconut
.
Erwartete Ausgabe:
coconut
apple
juice
mango
something
Ich habe es mit Folgendem versucht, aber es löscht nur die beiden obigen Zeilen und nicht genau die, nach der ich suche.
tac foo.txt |sed '/juice/I,+2 d' |tac
mango
something
Ich denke, dass eine Anpassung des obigen Skripts das Problem lösen würde, bin mir aber nicht sicher.
Hinweis: Die Übereinstimmung wird nicht wiederholt und muss keine exakte Übereinstimmung sein (d. h., die Übereinstimmung kann auch in einer langen Zeile gefunden werden). Bei der Übereinstimmung muss die Groß-/Kleinschreibung beachtet werden.
Antwort1
Wenn ed
das in Ordnung ist, müssen Sie eine Datei bearbeiten, keinen Stream, und es gibt nur einen juice
:
$ more <<-EOF | ed -s ./tmp.txt
/juice/
-2
c
coconut
.
w
q
EOF
$
Suchen Sie die Linie, gehen Sie zwei Linien nach oben, c
hängen Sie,
w
ritieren Sie und q
verlassen Sie sie.
Eine noch kompaktere Variante, vorgeschlagen von @d-ben-knoble in den Kommentaren:
$ printf '%s\n' '/^juice$/-2s/.*/coconut/' w q | ed -s ./tmp.txt
Antwort2
Nach Ihrem Ansatz,
tac file|sed '/juice/{n;n;s/.*/coconut/}'|tac
/juice/
stimmt mit einer Zeile mit übereinjuice
.n;n;
druckt die aktuelle und die nächste Zeile.s/.*/coconut/
nimmt die Auswechslung vor.
Anscheinend hast du GNU sed, also könntest du auch verwenden, -z
um die ganze Datei in den Speicher zu bekommen und direkt die Zeile zwei über juice zu bearbeiten,
sed -rz 's/[^\n]*(\n[^\n]*\n[^\n]*juice)/coconut\1/' file
[^\n]
bedeutet „keine neue Zeile“ und die Klammern erfassen die durch die Rückreferenz ()
reproduzierte Gruppe .\1
Antwort3
$ tac file | awk 'c&&!(--c){$0="coconut"} /juice/{c=2} 1' | tac
coconut
apple
juice
mango
something
Antwort4
Hier ist ein weiterer awk
Ansatz, diesmal eine Double-Pass-Methode:
awk 'NR==FNR&&/juice/{m=FNR} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file
- Wir geben die Datei anzweimalals Befehlszeilenargumente, sodass es zweimal verarbeitet wird.
- Im ersten Durchgang (wobei
FNR
, der Zeilenzähler pro Datei, gleichNR
, dem globalen Zeilenzähler ist) ermitteln wir einfach, in welcher Zeile das Suchmusterjuice
auftritt, und speichern es in einer Variablenm
. - Im zweiten Durchgang setzen wir die Zeilennummer
m-2
auf den Ersetzungstextcoconut
. - Als allgemeine Regel drucken wir die Zeilen einschließlich aller Änderungen, aber nur im zweiten Durchgang (wenn die Bedingung
NR>FNR
als „wahr“ ausgewertet wird).
Wenn Sie GNU haben awk
(einige andere awk
Implementierungen unterstützen dies ebenfalls), können Sie den Vorgang etwas beschleunigen, indem Sie den ersten Durchgang abbrechen, sobald die Übereinstimmung mit dem folgenden nextfile
Befehl gefunden wurde:
awk 'NR==FNR&&/juice/{m=FNR;nextfile} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file