Ik gebruik dit
cat foo.txt | sed "/bar/d"
om regels te verwijderen die de string bar
in het bestand bevatten.
Ik zou echter die regels en de regel direct willen verwijderen erna . Bij voorkeur in sed
, awk
of een andere tool die beschikbaar is in MinGW32.
Het is een soort omgekeerde van wat ik kan krijgen in grep
met -A
en -B
om ook overeenkomende regels af te drukken als regels voor / na de overeenkomende regel.
Is er een gemakkelijke manier om dit te bereiken?
Opmerkingen
- Alleen voor informatie: ik ‘ m analyseer logboeken waarin vermeldingen twee-liners zijn. Dus ik wil een item vinden dat overeenkomt met het patroon en dit verwijderen, evenals de volgende regel. Daarom hoef ik ‘ niet opeenvolgende wedstrijdregels te verwerken, maar toch bedankt voor de volledigheid van uw antwoorden!
Antwoord
Als je GNU sed hebt (dus niet-embedded Linux of Cygwin):
sed "/bar/,+1 d"
Als je bar
op twee opeenvolgende regels hebben, dit zal de tweede regel verwijderen zonder deze te analyseren. Als u bijvoorbeeld een bestand van 3 regels heeft bar
/ bar
/ foo
, de regel foo
blijft staan.
Reacties
- +1 voor de lengte 🙂 In mijn bijzonder voorbeeld Ik heb ‘ geen opeenvolgende
bar
s, dus deze is super gemakkelijk te onthouden. -
sed '/bar/d'
als je alleen ” regel wilt verwijderen die een bepaalde string bevat ” en niet de volgende. - Als ik alle regels na wiskunde wil verwijderen, dan?
- @Pandya Dat ‘ is anders. U kunt b.v.
sed '/math/q'
- @ A.K. Als u alleen de overeenkomende regel wilt verwijderen, is deze ‘ nog eenvoudiger:
sed '/bar/d'
Answer
Als bar
kan voorkomen op opeenvolgende regels, zou je het volgende kunnen doen:
awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile
die kan worden aangepast om meer dan 2 regels te verwijderen door de 2 hierboven te wijzigen met het aantal te verwijderen regels inclusief de overeenkomende.
Zo niet, dan “s gemakkelijk te doen in sed
met @MichaelRollins” -oplossing of:
sed "/bar/,/^/d" < infile > outfile
Reacties
- Het andere pluspunt van de AWK-oplossing is dat ik
/bar/
kan vervangen door/bar|baz|whatever/
. Insed
lijkt die syntaxis ‘ niet te werken. - @ jakub.g, ik heb GNU sed ( v4.4 nu). Niet zeker van de anderen. Wat ik weet is dat het standaard ” basic ” syntaxis voor reguliere expressies gebruikt. Dit is waarom uw voorbeeld ‘ t werk. Om te bereiken wat u wilt, kunt u een backslash voor elke verticale lijn plaatsen of u kunt
sed
vragen om ” extended ” reguliere expressies. Meer informatie hier: gnu.org/software/sed/manual/html_node/… . Houd er rekening mee dat dit ook van toepassing is opgrep
. Hier ‘ is mijn eigen werkvoorbeeld:echo $'0a\n1b\n2c' | sed '/0a\|1b/d'
.
Antwoord
Ik spreek sed niet vloeiend, maar het is gemakkelijk om dit in awk te doen:
awk "/bar/{getline;next} 1" foo.txt
De awk-script luidt: voor een regel die een balk bevat, haalt u de volgende regel op (getline) en slaat u alle volgende bewerkingen over (volgende). Het 1-patroon aan het einde drukt de resterende regels af.
Update
Zoals aangegeven in de opmerking, werkte de bovenstaande oplossing niet met opeenvolgende bar
. Hier is een herziene oplossing, die er rekening mee houdt:
awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt
We blijven nu lezen om alle / bar / regels over te slaan.
Opmerkingen
- Om
grep -A
100% te repliceren, moet u ook een willekeurig aantal opeenvolgendebar
regels correct (door het hele blok en 1 regel erna te verwijderen).
Antwoord
U zult de scriptmogelijkheden van sed willen gebruiken om dit te bereiken.
$ sed -e "/bar/ { $!N d }" sample1.txt
Voorbeeldgegevens:
$ cat sample1.txt foo bar biz baz buz
Het “N” -commando voegt de volgende invoerregel toe aan de patroonruimte. Dit gecombineerd met de lijn uit de patroonovereenkomst (/ bar /) zullen de lijnen zijn die u wilt verwijderen. U kunt dan verwijder normaal met het “d” commando.
Reacties
- Hoe typ ik een nieuwe regel in de console? Of is dit alleen script?
- @ jakub.g: met GNU sed:
sed -e '/bar/{N;d}' sample1.txt
Antwoord
Als een regel direct na een match verwijderd moet worden, dan zal je sed
programma opeenvolgende matches moeten overwegen. Met andere woorden, als u een regel verwijdert die volgt op een overeenkomst die ook overeenkomt, dan moet u waarschijnlijk de volgende regel ook verwijderen.
Het is eenvoudig genoeg geïmplementeerd – maar u moet een beetje achterom kijken .
printf %s\\n 0 match 2 match match \ 5 6 match match match \ 10 11 12 match 14 15 | sed -ne"x;/match/!{g;//!p;}"
0 6 11 12 15
Het werkt door de hold- en patroonruimten voor elke ingelezen regel om te wisselen – zodat de laatste regel elke keer met de huidige kan worden vergeleken. Dus als sed
een regel leest, wisselt het de inhoud van zijn buffers uit – en de vorige regel is dan de inhoud van zijn bewerkingsbuffer, terwijl de huidige regel in de wachtruimte wordt geplaatst.
Dus sed
controleert de vorige regel op een overeenkomst met match
, en als zijn !
niet gevonden de twee expressies in de {
functie }
worden uitgevoerd. sed
zal g
de hold-ruimte etsen door de patroonruimte te overschrijven – wat betekent dat de huidige regel zich dan in zowel de hold- als de patroonruimte bevindt – en dan zal het //
controleren of het overeenkomt met de meest recent gecompileerde reguliere expressie – match
– en als het niet match
het p
rint.
Dit betekent dat een regel alleen wordt afgedrukt als deze niet match
en de direct vorige regel niet match
. Het ziet ook af van onnodige swaps voor reeksen match
es.
Als je een versie wilde die een willekeurig aantal regels zou kunnen laten vallen optreden na een match
zou het wat meer werk vergen:
printf %s\\n 1 2 3 4 match \ match match 8 \ 9 10 11 12 13 \ 14 match match \ 17 18 19 20 21 | sed -net -e"/match/{h;n;//h;//!H;G;s/\n/&/5;D;}" -ep
. .. vervang de 5 door het aantal regels (inclusief de overeenkomende regel) dat u wilt verwijderen …
1 2 3 4 12 13 14 21