Odeberte řádek obsahující určitý řetězec a následující řádek

Používám tento

cat foo.txt | sed "/bar/d"

odstranit řádky obsahující řetězec bar v souboru.

Chtěl bych však tyto řádky odstranit a řádek přímo po tom . Nejlépe v sed, awk nebo v jiném nástroji, který je k dispozici v MinGW32.

Je to druh reverzu toho, co můžu dostat do grep pomocí -A a -B a také k tisku odpovídajících řádků jako řádky před / za shodným řádkem.

Existuje nějaký snadný způsob, jak toho dosáhnout?

Komentáře

  • Jen pro informace: ' m analyzuji protokoly, ve kterých jsou položky dvouřádkové. Takže chci najít položku odpovídající vzoru a odstranit ji i další řádek. Proto nepotřebuji ' zpracovávat po sobě jdoucí shodné řádky, ale stejně děkuji za úplnost vašich odpovědí!

Odpovědět

Pokud máte GNU sed (tedy nevložený Linux nebo Cygwin):

sed "/bar/,+1 d" 

Pokud máte mít bar na dvou po sobě následujících řádcích, tím odstraníte druhý řádek bez jeho analýzy. Například pokud máte třířádkový soubor bar / bar / foo, řádek foo zůstane.

Komentáře

  • +1 pro délku 🙂 Z mého pohledu příklad Nemám ' po sobě jdoucí bar s, takže tento je velmi snadno zapamatovatelný.
  • sed '/bar/d' pokud chcete " odebrat řádek obsahující určitý řetězec " a ne další.
  • Pokud chci po matematice odstranit všechny řádky, pak?
  • @Pandya To je ' jiné. Můžete použít např. sed '/math/q'
  • @ A.K. Pokud chcete pouze smazat odpovídající řádek, je ' ještě jednodušší: sed '/bar/d'

Odpověď

Pokud se bar může vyskytnout na po sobě následujících řádcích, můžete:

awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile 

který lze upravit tak, aby smazal více než 2 řádky změnou výše uvedených 2 s počtem řádků, které chcete smazat, včetně odpovídajícího.

Pokud ne, je „lze snadno provést v sed s @MichaelRollins“ řešením nebo:

sed "/bar/,/^/d" < infile > outfile 

Komentáře

  • Další výhodou řešení AWK je, že mohu nahradit /bar/ /bar|baz|whatever/. V sed se zdá, že syntaxe ' nefunguje.
  • @ jakub.g, mám GNU sed ( v4.4 nyní). Nejsem si jistý ostatními. Vím však, že ve výchozím nastavení používá " základní " syntaxi regulárního výrazu, proto váš příklad ' nefunguje. Chcete-li dosáhnout toho, co chcete, můžete před každou svislou čáru umístit zpětné lomítko nebo můžete požádat sed o použití " extended " regulární výrazy. Více informací zde: gnu.org/software/sed/manual/html_node/… . To platí také pro grep. Zde ' je můj vlastní pracovní příklad: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.

Odpovědět

Neumím plynule, ale v awk je to snadné:

awk "/bar/{getline;next} 1" foo.txt 

awk skript zní: pro řádek obsahující lištu, získejte další řádek (getline), pak přeskočte veškeré následné zpracování (další). Vzor 1 na konci vytiskne zbývající řádky.

Aktualizovat

Jak bylo uvedeno v komentáři, výše uvedené řešení nefungovalo s po sobě jdoucími bar. Zde je revidované řešení, které jej zohledňuje:

awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt 

Nyní pokračujeme ve čtení, abychom přeskočili všechny řádky / bar /.

Komentáře

  • Chcete-li replikovat grep -A 100%, musíte také zpracovat libovolný počet po sobě jdoucích bar řádky správně (odstraněním celého bloku a 1 řádku za ním).

Odpovědět

Chcete-li toho dosáhnout, budete chtít využít možnosti skriptování sed.

$ sed -e "/bar/ { $!N d }" sample1.txt 

Ukázková data:

$ cat sample1.txt foo bar biz baz buz 

Příkaz „N“ připojí další řádek vstupu do prostoru vzoru. To v kombinaci s řádkem ze shody vzoru (/ bar /) budou řádky, které chcete smazat. Poté můžete běžně mazat pomocí příkazu „d“.

Komentáře

  • Jak v konzole zadám nový řádek? Nebo je to pouze skript?
  • @ jakub.g: s GNU sed: sed -e '/bar/{N;d}' sample1.txt

Odpověď

Pokud by měl být odstraněn jakýkoli řádek bezprostředně následující po shodě, bude váš program sed muset vzít v úvahu po sobě jdoucí shody. Jinými slovy, pokud odstraníte řádek, který následuje po shodě, která také odpovídá, pravděpodobně byste také měli odstranit řádek, který následuje.

Je implementován jednoduše – ale musíte se trochu podívat .

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  

Funguje to tak, že se pro každý načtený řádek vymění zadržovací a vzorové prostory – takže poslední řádek lze pokaždé porovnat s aktuálním. Když tedy sed přečte řádek, vymění si obsah svých vyrovnávacích pamětí – a předchozí řádek je pak obsahem jeho editační vyrovnávací paměti, zatímco aktuální řádek je umístěn v pozdrženém prostoru.

Takže sed zkontroluje shodu předchozího řádku s match , a pokud jeho ! nenalezeny dva výrazy ve { funkci } jsou spuštěny. sed vytvoří g zadržovací prostor přepsáním vzorového prostoru – což znamená, že aktuální řádek je pak v zadržovacím i vzorovém prostoru – a poté // zkontroluje shodu s jeho naposledy zkompilovaným regulárním výrazem – match – a pokud to není match je p rinted.

To znamená, že se řádek vytiskne, pouze pokud match a bezprostředně předchozí řádek match . Rovněž se vzdává zbytečných swapů pro sekvence match es.

Pokud byste chtěli verzi, která by mohla vynechat libovolný počet řádků vyskytující se po match by to vyžadovalo trochu více práce:

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 

. ..změňte 5 s počtem řádků (včetně shodného řádku) , které chcete odebrat …


1 2 3 4 12 13 14 21 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *