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.