Sed: substituir padrão em cada segunda nova linha?

10

Existe uma maneira de dizer sedpara substituir o padrão em cada segunda ocorrência? Ou pelo menos em cada segunda linha? (Claro que é possível com um script, mas eu estava me perguntando se sedposso fazê-lo).

Editar

eu encontrei

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

Mas substituiu toda primeira ocorrência, não a segunda.

Exemplo

Arquivo de entrada:

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

Saída desejada:

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
fonte

Respostas:

6

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

A solução usa awk em vez de sed, mas "use a ferramenta certa para o trabalho". Pode ou não ser possível fazer no sed, mas, mesmo que seja, será muito mais fácil em uma ferramenta como awk ou perl.

cas
fonte
1
Usando o que eu aprendi lá eu empregada sed -e 'n;s/2004-2009/6e législature/g'que resolveu meu problema.
Matthieu Riegler
1
que não receberá cada segunda ocorrência , ele procurará seu padrão a cada segunda linha . pule as linhas 1, 3, 5, 7, etc. claro, isso ainda pode funcionar para o seu documento em particular.
cas
Sim, eu sei. era disso que eu precisava.
Matthieu Riegler
14
sed 's/pattern/replacement/2'

Substituirá a segunda ocorrência em todas as linhas que possuem o padrão.


se você tem GNU sed:

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

A partir da linha um 1, a linha após ser adicionada ao espaço do padrão N, o scomando substituirá a segunda ocorrência do padrão. depois sedmoverá duas linhas para baixo ~2e repetirá.

llua
fonte
Não quero o segundo, mas cada segundo.
Matthieu Riegler
Eu tenho um padrão por linha. Isso não vai funcionar.
Matthieu Riegler
Teria sido bom saber disso antes. Então o padrão acontece na linha um, dois, três e quatro (etc), e você deseja substituir o padrão na linha dois, quatro, etc?
llua
uma alternativa mais curta pode ser code(sed '1 ~ 2s / padrão / substituição /') #
22415
2

A simples interpretação:

Na primeira linha que contém pelo menos uma ocorrência de PATTERN, você deseja ignorá-la e imprimir a linha como está. Na segunda linha que contém pelo menos uma ocorrência de PATTERN, você deseja substituir a primeira instância de PATTERN por REPLACEMENT. Na terceira linha que contém pelo menos uma ocorrência de PATTERN, você deseja imprimir a linha como está. Na quarta linha que contém pelo menos uma ocorrência de PATTERN, você deseja substituir a primeira instância de PATTERN por REPLACEMENT. E assim por diante. As linhas que não correspondem ao PADRÃO devem ser impressas sem alterações.

Isso pode ser feito facilmente com o Sed, da seguinte maneira:

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

Ou, com menos espaço em branco e um rótulo mais curto:

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

Edição: Acabei de reler a pergunta e vi a interpretação mais difícil:

Substitua a segunda ocorrência de PATTERN no documento inteiro por REPLACEMENT, se ela ocorre na mesma linha da primeira ocorrência ou não. Deixe a primeira e a terceira ocorrências inalteradas. Etc.

Acredito que isso possa ser feito com o Sed também, embora seja MUITO mais complicado e acredito que depende da expressão regular a ser usada. Vou tentar resolver alguma coisa e publicá-la, mas deixarei que esta resposta permaneça com a versão simples acima, por enquanto.

Curinga
fonte
substitua seu test por um quit e { sed '...'; cat; } <input
aceite
1

Você estava muito perto, apenas pule a primeira linha:

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

Por que deveria awkser a melhor ferramenta neste caso?

Philippos
fonte
0

Um padrão de símbolo dentro de uma linha: sed 's / (a ​​[^ a] *) a / \ 1c / g'

Cada segundo padrão (apenas uma correspondência de padrão por linha pode aparecer. Se duas ou mais correspondências por uma linha aparecerem, apenas a segunda será substituída)

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;}'
pressa
fonte