Kommentiere alle Zeilen von zuletzt kommentierter Zeile zu Zeile mit 'foo'


12

Betrachten Sie eine Textdatei users.txt:

#alice
#bob
charlie
dotan
eric

Ich muss alles von (exklusiv) der zuletzt kommentierten Zeile bis (inklusive) kommentieren dotan. Das ist das Ergebnis:

#alice
#bob
#charlie
#dotan
eric

Gibt es dafür einen netten sedOneliner? Ich werde mit jedem Werkzeug glücklich sein, nicht nur sedwirklich.

Momentan erhalte ich die Zeilennummer der zuletzt kommentierten Zeile wie folgt:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

Ich füge dann einen hinzu und kommentiere mit sed:

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

Ich weiß, dass ich klug sein und das alles mit einigen bczu einem hässlichen Einzeiler zusammenfügen könnte. Sicherlich muss es einen saubereren Weg geben?

Antworten:


5

Wie wäre es mit

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

oder die gleiche Idee in awk:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

7

Wenn die vorhandenen kommentierten Zeilen einen einzelnen zusammenhängenden Block bilden, können Sie stattdessen eine Übereinstimmung mit der ersten kommentierten Zeile herstellen und nur die Zeilen bis einschließlich Ihres Endmusters auskommentieren, die noch nicht kommentiert sind

sed '/^#/,/dotan/ s/^[^#]/#&/' file

Wenn die vorhandenen Kommentare nicht zusammenhängend sind, dann müssten Sie aufgrund der gierigen Natur des Sed Range Matchs meines Erachtens so etwas tun

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

dh vom Endmuster bis zum 'ersten' Kommentar nach oben abgleichen - das ist natürlich nicht so praktisch, wenn Sie jedoch eine In-Place-Lösung wünschen.


4

Sie können beide Fälle (kommentierte Zeilen in einem zusammenhängenden Block oder zwischen unkommentierten Zeilen) mit einem einzigen sedAufruf behandeln:

sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile

Dadurch werden nur die Zeilen im 1,/PATTERN/Bereich verarbeitet. Es xändert sich der Laderaum w. Musterabstand jedes Mal, wenn eine Zeile kommentiert wird (es gibt also nie mehr als eine kommentierte Zeile im Haltepuffer) und fügt jede Zeile, die nicht kommentiert ist, an den Halten Abstand an (wenn in der ersten Zeile 1dbzw. 1herforderlich, um die Initiale zu entfernen) leere Zeile im Haltepuffer).
Wenn es die Linie Anpassungsmuster erreicht, es hängt es auch mit dem Halten Puffer, e xdie Puffer ändert und ersetzt dann jeden \newline Charakter in dem Musterraum mit einem \newline und einem #(das heißt, werden alle Linien in Musterraum jetzt beginnen mit #, Einschließen der ersten Zeile als erste Zeile im Laderaum ist immer eine kommentierte Zeile.
Mit einer Probe infile:

alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry

Laufen:

sed '1,/dotan/{                   # if line is in this range    -start c1
/^#/{                             # if line is commented        -start c2
x                                 # exchage hold space w. pattern space
1d                                # if 1st line, delete pattern space
b                                 # branch to end of script
}                                 #                             -end c2
//!{                              # if line is not commented    -start c3
H                                 # append to hold space
/dotan/!{                         # if line doesn't match dotan -start c4
1h                                # if 1st line, overwrite hold space
d                                 # delete pattern space
}                                 #                             -end c4
//{                               # if line matches dotan       -start c5
x                                 # exchage hold space w. pattern space
s/\n/&#/g                         # add # after each newline character
}                                 #                             -end c5
}                                 #                             -end c3
}' infile                         #                             -end c1

Ausgänge:

alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry

Daher werden nur Zeilen von (und ohne) #charliebis (und mit) kommentiert dotanund die anderen Zeilen bleiben unverändert.
Natürlich wird davon ausgegangen, dass vor der Zeilenübereinstimmung immer mindestens eine kommentierte Zeile vorhanden ist PATTERN. Wenn dies nicht der Fall ist, können Sie vor dem Austausch eine zusätzliche Prüfung hinzufügen:/^#/{s/\n/&#/g}


Vielen Dank, aus dieser Antwort kann ich einiges lernen!
Dotancohen

Warte, ich muss es vermasselt haben. Hier geht es nicht um die letzte Reihe kommentierter Zeilen? Nein, ich verstehe schon. Die letzte Serie + Dotan. Ziemlich schlau.
mikeserv

1
Sie finden immer die besten Fragen. Verdammter Dotan hat mich für eine Weile geworfen - vielleicht immer noch, ich habe es noch nicht getestet. Danke, Don.
mikeserv

2

Hier ist eine andere sed:

sed  -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn'      \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et  -e\} -eP\;D <in >out

Das macht was du fragst. Es funktioniert nur auf einem Stapel - es wird bei Bedarf und so lange wie nötig zwischen den Vorkommen kommentierter Zeilen aufgebaut und der alte Puffer zugunsten der neuen kommentierten Zeile weiter in der Eingabe ausgegeben, wenn er eine findet. Bild...

Bildbeschreibung hier eingeben

Entschuldigung, ich weiß nicht warum ich das getan habe. Aber es kam mir in den Sinn.

Auf sedjeden Fall werden die Puffer zwischen den zuletzt kommentierten Zeilen einer Reihe verteilt, und es wird nie mehr in den Puffer geschrieben, als zur genauen Verfolgung des zuletzt kommentierten Ereignisses erforderlich ist. Stößt das Programm dabei zu irgendeinem Zeitpunkt auf die letzte Zeile, versucht es dies endgültige globaler Ausführung Anweisung und Zweig test puffern die ganze gedruckt werden aus, sonst wird es Pall diese Linien RINT es aus seinem Puffer freigibt , sobald es tut.

Ich denke, das hat die Akkordeons in den Sinn gebracht ...

printf %s\\n   \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric |
sed  -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn'     \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g'  \
-et  -e\} -eP\;D

#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric

Es gibt nur einen Unterschied zwischen diesem und dem obigen Befehl und das ist der lBefehl ook oben. Wenn wir uns den Pattern Space lanschauen sed, wie er funktioniert, können wir eine bessere Vorstellung davon bekommen, was sich hinter den Kulissen abspielt, und ein besseres Verständnis dafür, wie man seine Bemühungen lenkt.

In diesem Fall können wir die sedStapeleingabe beobachten , bis ein zweites Vorkommen der \n#.*\ndotanEingabe gefunden wurde, und zwar dann, wenn der Ausdruck der vorherigen Zeile zu einem Zeitpunkt beginnt. Es ist irgendwie cool. Daran habe ich viel gelernt.


Sehr Schön. Danke! Der letzte Abschnitt mit den Erklärungen ist großartig, ich werde auch einige Zeit damit verbringen, aus diesem Beitrag zu lernen. Schöner Stapel!
Dotancohen

1
@dotancohen - das war eine wirklich gute Frage. Schauen Sie sich die Bearbeitung an, um den Stapel zu sehen .
mikeserv

2
Ich bemerke im Bearbeitungsverlauf den Eintrag Handle many dotans. Ich bin sicher, dass dies der schlimmste Albtraum meiner Frau ist.
Dotancohen

1
@dotancohen - ja, das war eine schwierige Frage. Sachen wie #\ndotan\ndotanist schwer für diese Dinge. Ich meine es ernst, wenn ich das eine gute Frage sage. Ich denke, ich habe es fast perfekt verstanden, aber ein Problem, auf das Sie stoßen könnten , ist, wenn Ihre Kommentarblöcke durch 1000 Zeilen getrennt sind - das wird es verlangsamen. Sie können beispielsweise s/\n/&/150;tvor dem ersten /\n#Aufbrechen des Puffers so etwas wie hineinstecken, wenn er sich über 150 Zeilen erstreckt. Und vielleicht ist es auch nur das, worauf sie die ganze Zeit gewartet hat !
mikeserv
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.