Sed: Zastąpić wzór na każdej drugiej nowej linii?

10

Czy istnieje sposób, aby powiedzieć, sedaby zastąpić wzorzec przy co drugim wystąpieniu? A przynajmniej na co drugą linię? (Pewnie, że jest to możliwe dzięki skryptowi, ale zastanawiałem się, czy sedmogę to zrobić).

Edytować

znalazłem

sed -e "s/pattern/replacement/g;n"

Ale zastępuje to za każdym razem, a nie za drugim razem.

Przykład

Plik wejściowy:

I have a pattern in each line
Also the second line has the pattern
Another pattern here
And -- you guess it -- a pattern

Pożądane wyjście:

I have a pattern in each line
Also the second line has the replacement
Another pattern here
And -- you guess it -- a replacement
Matthieu Riegler
źródło

Odpowiedzi:

6

patrz /programming/5858200/sed-replace-every-nth-occurrence

Rozwiązanie wykorzystuje awk zamiast sed, ale „użyj odpowiedniego narzędzia do pracy”. Może być to niemożliwe , ale nawet jeśli tak jest, będzie to o wiele łatwiejsze w narzędziu takim jak awk lub perl.

cas
źródło
1
Korzystając z tego, czego się tam nauczyłem, pomogłem sed -e 'n;s/2004-2009/6e législature/g'rozwiązać problem.
Matthieu Riegler
1
który nie będzie pojawiał się co drugie wystąpienie , będzie szukał twojego wzoru w co drugim wierszu . tzn. pomiń pierwszą, trzecią, piątą, siódmą linię itd. oczywiście może to nadal działać w przypadku konkretnego dokumentu.
cas
Tak, wiem. właśnie tego potrzebowałem.
Matthieu Riegler,
14
sed 's/pattern/replacement/2'

Zastąpi drugie wystąpienie w każdej linii, która ma wzorzec.


jeśli masz GNU sed:

sed '1~2N ; s/pattern/replacement/2'

Począwszy od pierwszego wiersza 1, wiersz po nim zostanie dodany do obszaru wzorów, Na następnie spolecenie zastąpi drugie wystąpienie wzoru. następnie sedprzesunie się o dwie linie w dół ~2i powtórzy.

llua
źródło
Nie chcę sekundy, ale co sekundę.
Matthieu Riegler
Mam jeden wzór na linię. To nie zadziała.
Matthieu Riegler
byłoby miło wiedzieć o tym wcześniej. Więc wzór dzieje się na linii pierwszej, drugiej, trzeciej i czwartej (itd.), A chcesz zastąpić wzór na drugiej, czwartej itd.?
llua
krótszą alternatywą może być code(sed '1 ~ 2s / pattern / replace /')
jaap
2

Prosta interpretacja:

W pierwszym wierszu, który zawiera co najmniej jedno wystąpienie WZORCA, chcesz go zignorować i wydrukować taki, jaki jest. W drugim wierszu, który zawiera co najmniej jedno wystąpienie WZORU, chcesz zastąpić pierwsze wystąpienie WZORU WYMIANĄ. W trzecim wierszu, który zawiera co najmniej jedno wystąpienie WZORCA, chcesz wydrukować wiersz bez zmian. W czwartym wierszu, który zawiera co najmniej jedno wystąpienie WZÓR, chcesz zastąpić pierwsze wystąpienie WZORU zamieniem. I tak dalej. Linie, które nie pasują do WZORU, powinny być drukowane bez zmian.

Można to łatwo zrobić za pomocą Sed:

sed -e '/PATTERN/ { :inside' -e 'n;s//REPLACEMENT/;t' -e 'b inside' -e '}'

Lub z mniejszą ilością białych znaków i krótszą etykietą:

sed -e '/PATTERN/{:i' -e 'n;s//REPLACEMENT/;t' -e 'b i' -e '}'

EDYCJA: Właśnie przeczytałem pytanie i zauważyłem trudniejszą interpretację:

Zamień drugie wystąpienie WZORCA w całym dokumencie na WYMIANA, niezależnie od tego, czy występuje w tym samym wierszu co pierwsze wystąpienie, czy nie. Pozostaw pierwsze i trzecie wystąpienie bez zmian. Itp.

Sądzę, że można to zrobić również za pomocą Sed, chociaż jest DUŻO trudniejsze i uważam, że zależy to od używanego wyrażenia regularnego. Spróbuję coś wymyślić i opublikować, ale na razie pozwolę tej odpowiedzi stać na powyższą prostą wersję.

Dzika karta
źródło
zamień swój test na quit i weź dane wejściowe jak, { sed '...'; cat; } <inputdla jednego zamiennika
mikeserv
1

Byłeś bardzo blisko, po prostu pomiń pierwszą linię:

sed '1n;s/pattern/replacement/;n'

Dlaczego awkw tym przypadku powinno być lepsze narzędzie?

Philippos
źródło
0

Jeden wzór symboli w jednym wierszu: sed 's / (a ​​[^ a] *) a / \ 1c / g'

Co drugi wzór (może pojawić się tylko jedno dopasowanie wzoru na linię. Jeśli pojawią się dwa lub więcej dopasowań na jedną linię, tylko drugi zostanie zastąpiony)

echo -e "test\nreplace_me\ntest\ntest\nreplace_me\nreplace_me\nreplace_me" | \
sed '/replace_me/{:a;N;/replace_me.*replace_me/!Ta;s/replace_me/replaced/2;}'
wysypka
źródło