Jak zamienić linię w pliku wejściowym za pomocą sed / awk / perl

0

Próbuję zastąpić ścieżkę w pliku wejściowym.

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

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

Po zapoznaniu się z wcześniej udzielonym pytaniem ( https://stackoverflow.com/questions/11245144/replace-whole-line-containing-a-string-using-sed ).

Próbowałem tego.

    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

Wierzę, że sed / perl się myli, ale nie jestem pewien, jak to rozwiązać. Każda pomoc będzie mile widziana.

Vikas Dubey
źródło
Na co wcześniej odpowiedziałem na pytanie? Proszę być bardziej konkretnym.
phk
wspomniany pan !!
Vikas Dubey,

Odpowiedzi:

0

Jeśli używasz /jako ogranicznika sed, rozwiązaniem może być:

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

lub możesz użyć innego ogranicznika niż /, na przykład ::

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

Innym sposobem jest awk:

awk '{ gsub("../../../Plumed.h","/usr/local/include/Plumed.h"); print $0}' file
andreatsh
źródło
1

tl, dr:

Posługiwać się:

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

Kilka komentarzy na temat Twojej próby Sed:

sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg
  • -i nie jest przenośny, więc wygląda na to, że używasz GNU Sed.

    BSD Sed ma również -iprzełącznik, ale rozszerzenie kopii zapasowej jest wymaganym argumentem, więc modyfikacja pliku bez zapisywania kopii zapasowej w BSD Sed wymaga -i ''.

    Inne wersje Sed mogą -iw ogóle nie mieć przełącznika.

  • Wyrażenie regularne tutaj /../../../Plumed.h/zawiera wiele kopii ogranicznika wyrażenia regularnego.

    Typowym rozwiązaniem tego problemu jest uniknięcie separatora:

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

    Jest jednak mało znany fakt o Sed, że możesz użyć dowolnego znaku do ogranicznika wyrażenia regularnego (nie tylko w spoleceniu), jeśli odwrócisz ukośnik w pierwszej instancji. (Cóż, prawie każda — ukośnik odwrotny lub nowa linia jest niedozwolona).

    Aby bezpośrednio zacytować specyfikacje POSIX :

    W adresie kontekstowym konstrukcja „ \cBREc”, gdzie c jest dowolnym znakiem innym niż <backslash>lub <newline>, musi być identyczna z „ /BRE/”. Jeżeli znak oznaczony literą c pojawi się po znaku a <backslash>, wówczas będzie uważany za ten literalny znak, który nie powinien kończyć BRE. Na przykład w adresie kontekstowym „ \xabc\xdefx” drugi x oznacza siebie, więc BRE to „ abcxdef”.

    Aby uniknąć „zespołu pochylonych wykałaczek”, zauważ, że następujące dwa wyrażenia regularne są równoważne:

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

    Zauważ, że powiedziałem „odpowiednik” nie poprawne. To prowadzi mnie do następnego punktu, pominiętego w każdej innej odpowiedzi:

  • Kropka ( .) w wyrażeniu regularnym oznacza dowolną postać .

    Jeśli chcesz dopasować tylko literał, możesz albo uciec z kropki odwrotnym ukośnikiem, albo wkleić go do klasy postaci jak w [.].

    Zatem, aby dopasować tylko okresy dosłowne, wyrażenie regularne powinno być bardziej podobne do:

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

    Tyle o unikaniu pochylonych wykałaczek.

    Możesz także użyć prawdopodobnie bardziej czytelnej formy:

    \:[.][.]/[.][.]/[.][.]/Plumed[.]h:
  • cPolecenie zmienia całą linię , a nie tylko część linii dopasowane regex.

    Użyj spolecenia, aby zmienić tylko część linii.

    W szczególności dzięki spoleceniu nie musisz uciekać od pierwszego separatora wyrażenia regularnego (nawet w przypadku niezwykłego znaku używanego jako separator), tak jak w przypadku używania alternatywnego separatora w adresie.

    Co się tyczy cpolecenia, warto wiedzieć, że umieszczenie nowego tekstu w tym samym wierszu co c\rozszerzenie GNU jest nieprzenośne.


Podsumowując, możesz użyć spolecenia w następujący sposób:

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

Lub, jeśli chcesz być jeszcze bardziej wyraźny, możesz użyć zakotwiczonego wyrażenia regularnego i ckomendy hange, aby zmienić tylko całą linię:

sed -i '\:^#include "\.\./\.\./\.\./Plumed\.h"$:c\#include "/usr/local/include/Plumed.h"' ../dist0.xvg
Dzika karta
źródło
0

To polecenie działało dla mnie:

     sed -i 's#include "../../../Plumed.h"#include "/usr/local/include/Plumed.h"#g'
Vikas Dubey
źródło
0

Użyj wykrzyknika, jeśli w tekście jest wiele ukośników:

sed -e 's!../../../Plumed.h!/usr/local/include/Plumed.h!'
hschou
źródło