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.

Abe Voelker
fonte
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.

Joseph R.
fonte
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

Costas
fonte
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;"

Jeremy Davis
fonte