Como detectar o fim da linha com sed

6

Estou procurando uma maneira de executar somente a substituição quando o último caractere for uma nova linha, usando sed .

Por exemplo:

lettersAtEndOfLine

é substituído, mas isso não é:

lettersWithCharacterAfter&

Como sed não funciona bem com novas linhas, não é tão simples quanto

$ sed -E "s/[a-zA-Z]*\n/replace/" file.txt

Como isso pode ser feito?

    
por Matthew D. Scholefield 02.06.2015 / 01:43

4 respostas

13

Com o padrão sed , você nunca verá uma nova linha no texto lido de um arquivo. Isso ocorre porque sed lê linha por linha e, portanto, não há nova linha no final do texto da linha atual no espaço padrão em sed . Em outras palavras, sed lê dados delimitados por nova linha e os delimitadores não fazem parte do que um script sed vê.

Expressões regulares podem ser ancoradas no final da linha usando $ (ou no início, usando ^ ). Ancorar uma expressão no início / final de uma linha força-a a corresponder exatamente lá, e não apenas em qualquer lugar na linha.

Se você quiser substituir qualquer coisa que corresponda ao padrão [A-Za-z]* no final da linha com algo, então ancore o padrão da seguinte forma:

[A-Za-z]*$

... irá forçá-lo a combinar no final da linha e em nenhum outro lugar.

No entanto, como [A-Za-z]*$ também corresponde a nada (por exemplo, a string vazia presente no final de todas linhas), você precisa forçar a correspondência de < em> algo , por exemplo especificando

[A-Za-z][A-Za-z]*$

Então, a sua linha de comando sed será

$ sed 's/[A-Za-z][A-Za-z]*$/replace/' file.txt

Eu não usei a opção -E aqui porque não é necessária. Com isso, você poderia ter escrito

$ sed -E 's/[A-Za-z]+$/replace/' file.txt

É uma questão de gosto.

    
por 02.06.2015 / 09:41
1
sed "s/[a-zA-Z]*$/replace/" input.txt > result.txt

Ou, o longo caminho desnecessário complexo:

I've found out, this can be done, still using sed, with the help of tr. You can assign another character to represent the end of the line. Another temporary character has to be used, in this case "'". Let's use "~" to represent the end of the line:

tr '\n' ''' <input.txt >output.txt
sed -i "s/'/~'/" output.txt
tr ''' '\n' <output.txt >result.txt

And then to perform the actual search and replace, use "~" rather than "\n":

sed -i -E "s/[a-zA-Z]*~/replace/" result.txt

And then clean up the extra character on the other lines:

sed -i "s/~//" result.txt

Obviously, this can all be piped together resulting in something like:

tr '\n' ''' <input.txt | sed -e "s/'/~'/" | tr ''' '\n' | sed -E -e "s/[a-zA-Z]*~/replace/" | sed "s/~//" > result.txt
    
por 02.06.2015 / 01:43
0

Do snippet de código (quebrado) que você postou, parece que você quer substituir a nova linha também. Nesse caso, a ancoragem regex por si só não pode ajudá-lo. O seguinte é uma solução:

sed '/[[:alpha:]]\+$/{N;s/[[:alpha:]]\+\n/replace/}' your_file

Detalhado:

  • /[a-zA-Z]\+$/{} significa aplicar o que vem dentro dos curlies às linhas que correspondem ao regex.
  • O regex é aquele que usa a ancoragem como visto na sua própria resposta , modificada para levar comentários de glenn jackman em conta.
  • Dentro dos curlies, N significa "anexar a próxima linha ao buffer ativo" (o que sed chama de 'espaço de padrão')
  • Finalmente, a instrução s/// é a sua substituição obrigatória. Agora funciona porque o espaço de padrão contém duas linhas sucessivas e a nova linha é, portanto, uma parte dele.
por 02.06.2015 / 10:31
0

Para encontrar o fim da linha, use o $ - sign :

Sem âncora de fim de linha:

sed -n '/pattern/p' file 

Sem âncora de fim de linha:

sed -n '/pattern$/p' file
    
por 18.02.2018 / 14:27