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.

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

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

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

Jeremy Davis
fuente