GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo garantizar que la cadena interpolada en la sustitución 'sed' escape a todos los metacaracteres?

Tengo un script que lee un flujo de texto y genera un archivo de comandos sed que luego se ejecuta con sed -f . Los comandos sed generados son como:

s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/https://mysite.com/files/1924/g

Asumir el script que genera el sed comandos es algo así como:

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\./\\./g)"
    echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done

¿Cómo puedo mejorar el script para garantizar todos los metacaracteres regex en el cid? cadena se escapan y se interpolan correctamente?

Respuesta aceptada:

Para escapar de las variables que se utilizarán en el lado izquierdo y derecho de un s comando en sed (aquí $lhs y $rhs respectivamente), harías:

escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')

sed "s/$escaped_lhs/$escaped_rhs/"

Tenga en cuenta que $lhs no puede contener un carácter de nueva línea.

Es decir, en LHS, escape todos los operadores de expresión regular (][.^$* ), el propio carácter de escape ( ), y el separador (/ ).

En el RHS, solo necesita escapar & , el separador, la barra invertida y el carácter de nueva línea (lo que se hace insertando una barra invertida al final de cada línea excepto la última ($!s/$/\/ )).

Eso supone que usas / como separador en tu sed s comandos y que no habilites Res extendidos con -r (GNU sed /ssed /ast /busybox sed ) o -E (BSD, ast , GNU reciente, busybox reciente) o PCRE con -R (ssed ) o RE aumentados con -A /-X (ast ) que tienen operadores RE adicionales.

Algunas reglas básicas cuando se trata de datos arbitrarios:

  • No use echo
  • cita tus variables
  • considere el impacto del escenario (especialmente su juego de caracteres:es importante que el escape sed los comandos se ejecutan en la misma configuración regional que sed comando usando el escapó cadenas (y con el mismo sed comando) por ejemplo)
  • no se olvide del carácter de nueva línea (aquí puede comprobar si $lhs contiene alguno y tomar medidas).

Otra opción es usar perl en lugar de sed y pase las cadenas en el entorno y use el Q /E perl Operadores regexp para tomar cadenas literalmente:

A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'

perl (de forma predeterminada) no se verá afectado por el conjunto de caracteres de la configuración regional ya que, en lo anterior, solo considera las cadenas como matrices de bytes sin importar qué caracteres (si corresponde) pueden representar para el usuario. Con sed , podría lograr lo mismo fijando la configuración regional en C con LC_ALL=C para todos los sed comandos (aunque eso también afectará el idioma de los mensajes de error, si los hay).

Relacionado:¿Usar sed con caracteres especiales?
Linux
  1. ¿Cómo combinar todas las líneas que terminan con un carácter de barra invertida?

  2. ¿Cómo encontrar todos los archivos que no contienen una cadena de texto?

  3. Cómo reemplazar una cadena en varios archivos en la línea de comando de Linux

  4. Cómo mover todos los archivos, incluidos los archivos ocultos, al directorio principal a través de *

  5. ¿Cómo construir un módulo del kernel de Linux para que sea compatible con todas las versiones del kernel?

Cómo usar sed para buscar y reemplazar cadenas en archivos

Cómo usar Sed para buscar y reemplazar una cadena en un archivo

¿Cómo determinas el comando real que te está llegando?

Cómo encontrar archivos que no contienen una cadena de búsqueda determinada

Cómo capturar todos los discos que no tienen un sistema de archivos

¿Cómo obtener líneas que contienen cadenas en un archivo?