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/
. Vsed
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é progrep
. 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íchbar
řá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