Reemplazar el contenido del grupo de captura de expresiones regulares usando sed


16

Estoy tratando de editar mi archivo nginx.conf mediante programación, que contiene una línea como esta:

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

que quiero lucir así:

        access_log /dev/stdout;

Creo que la expresión regular ^\s*access_log([^;]*);capturará la /var/log/nginx/access.logparte en un grupo de captura, pero no estoy seguro de cómo reemplazar correctamente el grupo de captura con sed.

He intentado

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

pero recibo el error:

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

si lo intento, sed -rentonces no hay error, pero la salida no es lo que espero:

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

Estoy tratando de ser inteligente con el grupo de captura y otras cosas y no buscar directamente "access_log /var/log/nginx/access.log;" en caso de que la distribución cambie la ubicación predeterminada del archivo de registro.


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

@Costas ¡Si respondieras eso, te votaría porque eso también funciona!
— Abe Voelker

Respuestas:


16

Un par de errores allí.

En primer lugar, ya que sedutiliza expresiones regulares básicas, es necesario \(y \)hacer un grupo de captura. El -rmodificador habilita expresiones regulares extendidas, por lo que no obtiene el error. Consulte ¿Por qué necesito escapar de los caracteres regex en sed para ser interpretados como caracteres regex? .

En segundo lugar, está colocando el grupo de captura en el lugar equivocado. Si te entiendo correctamente, puedes hacer esto:

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

Tenga en cuenta el uso de !delimitadores como expresiones regulares para evitar tener que escapar de las barras diagonales /dev/stdout.


Gracias, funciona de maravilla! Todavía no puedo marcar esto como aceptado, pero volveré en 9 minutos para hacerlo.
— Abe Voelker

1
@AbeVoelker De nada. Me alegro de poder ayudar.
— Joseph R.

5

En tu expresión regular debes saber que \No. es la referencia posterior al patrón entre paréntesis (). Entonces regexp debería ser's@^(\s*access_log ).*$@\1/dev/stdout/;@'

Puedo ofrecer

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

SUGERENCIA: Si tiene la intención de usar /dentro del patrón, puede cambiarlo s///por cada símbolo que desee, s###por ejemplo


Gracias, ¡ojalá pudiera aceptar dos respuestas! Ya no me arrepiento de no haber leído completamente las páginas de manual antes de pedir ayuda después de ver las soluciones.
— Abe Voelker

3

En lugar de capturarlo, ¿por qué no solo encontrarlo y hacer una sustitución? Es decir:

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

Busca líneas que coinciden con " access_log" y luego en cualquier línea que lo haga reemplazará " /whatever/path/is/there;" con " /dev/stdout;"

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.