Substitua o conteúdo do grupo de captura de regex usando sed


16

Estou tentando editar meu arquivo nginx.conf programaticamente, que contém uma linha como esta:

        access_log /var/log/nginx/access.log;

que eu quero ficar assim:

        access_log /dev/stdout;

Acredito que o regex ^\s*access_log([^;]*);capturará a /var/log/nginx/access.logparte em um grupo de captura, mas não sei como substituir corretamente o grupo de captura por sed?

eu tentei

echo "        access_log /var/log/nginx/access.log;" | sed 's/^\s*access_log([^;]*);/\1\\\/dev\\\/stdout/'

mas estou recebendo o erro:

sed: -e expression #1, char 45: invalid reference \1 on `s' command's RHS

se eu tentar sed -r, não haverá erro, mas a saída não é o que eu espero:

 /var/log/nginx/access.log\/dev\/stdout

Estou tentando ser inteligente com o grupo de captura e outros enfeites e não procurar diretamente por "access_log /var/log/nginx/access.log;" caso a distribuição altere o local padrão do arquivo de log.


11
sed '/access_log/s|/[^;]\+|/dev/stdout|'
— Costas

@Costas Se você der uma resposta, eu o recomendo, pois isso também funciona!
— precisa

Respostas:


16

Alguns erros lá.

Primeiro, como sedusa expressões regulares básicas, você precisa \(e \)deve criar um grupo de captura. A -ropção permite expressões regulares estendidas e é por isso que você não recebe o erro. Consulte Por que preciso escapar caracteres regex no sed para ser interpretado como caracteres regex?.

Segundo, você está colocando o grupo de captura no lugar errado. Se eu entendi direito, você pode fazer o seguinte:

sed -e 's!^\(\s*access_log\)[^;]*;!\1 /dev/stdout;!' your_file

Observe o uso de !como delimitadores de expressão regular para evitar a necessidade de escapar das barras /dev/stdout.


Obrigado, funciona maravilhosamente! Ainda não posso marcar isso como aceito, mas voltarei em 9 minutos para fazer isso.
— Abe Voelker

11
@AbeVoelker De nada. Estou feliz por poder ajudar.
— Joseph R.

5

Em sua regexp, você deve saber que \No.é a referência anterior ao padrão entre colchetes() . Então regexp deve ser's@^(\s*access_log ).*$@\1/dev/stdout/;@'

Eu posso oferecer

sed '/access_log/s|/[^;]\+|/dev/stdout|'

DICA: Se você pretende usar /dentro do padrão, pode mudar s///para cada símbolo que desejar, s###por exemplo


Obrigado, gostaria de poder aceitar duas respostas! Não me arrependo de não ter lido completamente as páginas de manual antes de pedir ajuda depois de ver as soluções.
— Abe Voelker

3

Em vez de capturá-lo, por que não encontrá-lo e fazer uma substituição? Ou seja:

sed "/access_log/ s| /.*;| /dev/stdout;|"

Ele procura por linhas que correspondam " access_log" e, em qualquer linha que o substitua, " /whatever/path/is/there;" por " /dev/stdout;"

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.