Cómo reemplazar una línea en un archivo de entrada usando sed/awk/perl

Cómo reemplazar una línea en un archivo de entrada usando sed/awk/perl

Estoy intentando reemplazar una ruta en un archivo de entrada.

    #include "../../../Plumed.h"         #### this is old patch in input 

    #include "/usr/local/include/Plumed.h  #### this should be the new path

Después de ver la pregunta respondida anteriormente (https://stackoverflow.com/questions/11245144/replace-whole-line-containing-a-string-using-sed).

Intenté esto.

    sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg


    perl -i -pe 's/../../../Plumed.h/usr/local/include/Plumed.h/g' ../dist0.xvg

Creo que sed/perl se está confundiendo, pero no estoy seguro de cómo solucionarlo. Cualquier ayuda será apreciada.

Respuesta1

tl, dr:

Usar:

sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg

Algunos comentarios sobre su intento de comando Sed:

sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg
  • -ino es portátil, por lo que parece que estás usando GNU Sed.

    -iBSD Sed también tiene un modificador, pero la extensión de la copia de seguridad es un argumento obligatorio, por lo que para modificar un archivo sin guardar una copia de seguridad en BSD Sed se requiere -i ''.

    Es posible que otras versiones de Sed no tengan ningún -iinterruptor.

  • La expresión regular aquí, /../../../Plumed.h/contiene varias copias del delimitador de expresiones regulares.

    La solución habitual a esto es escapar del delimitador:

    /..\/..\/..\/Plumed.h/
    

    Sin embargo, hay un hecho poco conocido sobre Sed, que puedes usarcualquiercarácter para el delimitador de expresiones regulares (no solo en el scomando) si se escapa la barra invertida en la primera instancia. (Bueno, casi cualquiera: no se permiten barras invertidas ni nuevas líneas).

    Para citar elEspecificaciones POSIXdirectamente:

    En una dirección de contexto, la construcción " \cBREc", dondeCes cualquier carácter distinto de <backslash>o <newline>, será idéntico a " /BRE/". Si el personaje designado porCaparece después de <backslash>, entonces se considerará que es ese carácter literal, que no dará por terminado el BRE. Por ejemplo, en la dirección de contexto " \xabc\xdefx", la segundaXse representa a sí mismo, por lo que el BRE es " abcxdef".

    Entonces, para evitar el "síndrome del palillo inclinado", tenga en cuenta que las dos expresiones regulares siguientes son equivalentes:

    /..\/..\/..\/Plumed.h/
    \:../../../Plumed.h:
    

    Tenga en cuenta que dije "equivalente".nocorrecto. Esto me lleva al siguiente punto, omitido en todas las demás respuestas:

  • Un punto ( .) en una expresión regular significacualquier personaje.

    Si desea hacer coincidir solo un punto literal, puede escapar de su punto con una barra invertida o insertarlo en una clase de caracteres como en [.].

    Por lo tanto, para que coincida sólo con períodos literales, la expresión regular debería ser más parecida a:

    \:\.\./\.\./\.\./Plumed\.h:
    

    Esto es suficiente para evitar los palillos inclinados.

    También puede utilizar la forma posiblemente más legible:

    \:[.][.]/[.][.]/[.][.]/Plumed[.]h:
    
  • El ccomando cambia ellinea completa, no solo la parte de la línea que coincide con la expresión regular.

    Utilice el scomando para cambiar solo una parte de una línea.

    En particular, con el scomando, no tiene que escapar de su primer delimitador de expresiones regulares (incluso para un carácter inusual usado como delimitador) como lo hace cuando usa un delimitador alternativo en una dirección.

    Además, con respecto al ccomando, vale la pena saber que incluir el nuevo texto en la misma línea que el c\es una extensión GNU y no es portátil.


Juntando todo esto, puedes usar el scomando así:

sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg

O, si quieres ser aún más explícito, puedes usar una expresión regular anclada y el ccomando Hange para cambiar solo la línea completa:

sed -i '\:^#include "\.\./\.\./\.\./Plumed\.h"$:c\#include "/usr/local/include/Plumed.h"' ../dist0.xvg

Respuesta2

Si está utilizando /como delimitador con sed, una solución podría ser:

sed -i 's/..\/..\/..\/Plumed.h/\/usr\/local\/include\/Plumed.h/g' file

o puede utilizar un delimitador diferente al de /, por ejemplo ::

sed -i 's:../../../Plumed.h:/usr/local/include/Plumed.h:g' file

Otra forma con awk:

awk '{ gsub("../../../Plumed.h","/usr/local/include/Plumed.h"); print $0}' file

Respuesta3

Este comando funcionó para mí:

     sed -i 's#include "../../../Plumed.h"#include "/usr/local/include/Plumed.h"#g'

Respuesta4

Utilice un signo de exclamación si hay muchas barras en el texto:

sed -e 's!../../../Plumed.h!/usr/local/include/Plumed.h!'

información relacionada