Como substituir uma linha em um arquivo de entrada usando sed / awk / perl

0

Estou tentando substituir um caminho em um arquivo de entrada.

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

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

Depois de ver a pergunta respondida anteriormente ( link ) .

Eu tentei isso.

    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

Eu acredito que o sed / perl está ficando confuso, mas não tenho certeza de como superar isso. Qualquer ajuda será apreciada.

    
por Vikas Dubey 30.10.2016 / 08:57

4 respostas

0

Se você estiver usando / como delimitador com sed , uma solução pode ser:

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

ou, você pode usar um delimitador diferente de / , por exemplo : :

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

Outra maneira com awk :

awk '{ gsub("../../../Plumed.h","/usr/local/include/Plumed.h"); print $0}' file
    
por 30.10.2016 / 10:19
1

tl, dr:

Uso:

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

Alguns comentários sobre sua tentativa de comando Sed:

sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg
  • -i não é portátil, então parece que você está usando o GNU Sed.

    O BSD Sed também possui uma opção -i , mas a extensão de backup é um argumento obrigatório, portanto, para modificar um arquivo sem salvar um backup no BSD Sed, é necessário -i '' .

    Outras versões do Sed podem não ter nenhuma mudança -i .

  • O regex aqui, /../../../Plumed.h/ , contém várias cópias do delimitador regex.

    A solução usual para isso é escapar do delimitador:

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

    No entanto, há um fato pouco conhecido sobre Sed, que você pode usar qualquer caractere para o delimitador regex (não apenas no comando s ) se você ignorar a primeira instância da barra invertida . (Bem, quase qualquer - barra invertida ou nova linha não é permitida).

    Para citar as especificações POSIX diretamente:

    In a context address, the construction "\cBREc", where c is any character other than <backslash> or <newline>, shall be identical to "/BRE/". If the character designated by c appears following a <backslash>, then it shall be considered to be that literal character, which shall not terminate the BRE. For example, in the context address "\xabc\xdefx", the second x stands for itself, so that the BRE is "abcxdef".

    Portanto, para evitar a "síndrome da paleta inclinada", observe que as duas expressões regulares a seguir são equivalentes:

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

    Note que eu disse "equivalente", não correto. Isso me leva ao próximo ponto, perdido em todas as outras respostas:

  • Um período ( . ) em uma expressão regular significa qualquer caractere .

    Se você quiser corresponder apenas a um período literal, pode fugir do período com uma barra invertida ou colocá-lo em uma classe de caractere como em [.] .

    Assim, para corresponder apenas a períodos literais, o regex deve ser mais parecido com:

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

    Tanto para evitar palitos inclinados.

    Você também pode usar o formato mais legível:

    \:[.][.]/[.][.]/[.][.]/Plumed[.]h:
    
  • O comando c altera a linha inteira , não apenas a parte da linha correspondida pela expressão regular.

    Use o comando s para alterar apenas uma parte de uma linha.

    Notavelmente, com o comando s , você não precisa escapar do primeiro delimitador de regex (mesmo para um caractere incomum usado como um delimitador) da maneira como você faz ao usar um delimitador alternativo em um endereço.

    Além disso, com relação ao comando c , vale a pena saber que incluir o novo texto na mesma linha que o c\ é uma extensão GNU e não portável.

Colocando tudo isso junto, você pode usar o comando s da seguinte forma:

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

Ou, se quiser ser ainda mais explícito, use uma regex ancorada e o comando c hange para alterar apenas a linha inteira:

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

Este comando funcionou para mim:

     sed -i 's#include "../../../Plumed.h"#include "/usr/local/include/Plumed.h"#g'
    
por 30.10.2016 / 12:00
0

Use o ponto de exclamação se houver muitas barras no texto:

sed -e 's!../../../Plumed.h!/usr/local/include/Plumed.h!'
    
por 30.10.2016 / 16:13

Tags