Ich versuche, einen Pfad in einer Eingabedatei zu ersetzen.
#include "../../../Plumed.h" #### this is old patch in input
#include "/usr/local/include/Plumed.h #### this should be the new path
Nach dem Lesen der zuvor beantworteten Frage (https://stackoverflow.com/questions/11245144/replace-whole-line-containing-a-string-using-sed).
Ich habe das versucht.
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
Ich glaube, sed/perl geraten durcheinander, aber ich bin nicht sicher, wie ich das lösen kann. Für jede Hilfe bin ich dankbar.
Antwort1
tl,dr:
Verwenden:
sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg
Einige Kommentare zu Ihrem versuchten Sed-Befehl:
sed -i '/../../../Plumed.h/c\/usr/local/include/Plumed.h' ../dist0.xvg
-i
ist nicht portierbar, daher sieht es so aus, als ob Sie GNU Sed verwenden.BSD Sed verfügt
-i
ebenfalls über einen Schalter, aber die Backup-Erweiterung ist ein erforderliches Argument. Um also eine Datei zu ändern, ohne ein Backup in BSD Sed zu speichern, ist erforderlich-i ''
.Andere Versionen von Sed haben möglicherweise
-i
überhaupt keinen Schalter.Der reguläre Ausdruck hier
/../../../Plumed.h/
enthält mehrere Kopien des Regex-Trennzeichens.Die übliche Lösung hierfür besteht darin, das Trennzeichen zu maskieren:
/..\/..\/..\/Plumed.h/
Es gibt jedoch eine wenig bekannte Tatsache über Sed, die Sie verwenden könnenbeliebigZeichen für das Regex-Trennzeichen (nicht nur im
s
Befehl), wenn Sie die erste Instanz mit einem Backslash maskieren. (Also, fast jedes – Backslash oder Zeilenumbruch sind nicht zulässig.)Um denPOSIX-Spezifikationendirekt:
In einer Kontextadresse wird die Konstruktion „
\cBREc
“ verwendet, wobeiCist ein beliebiges Zeichen außer<backslash>
oder<newline>
, muss identisch sein mit "/BRE/
". Wenn das durchCerscheint nach einem<backslash>
, dann wird es als das wörtliche Zeichen betrachtet, das den BRE nicht beenden soll. Beispielsweise in der Kontextadresse "\xabc\xdefx
" ist das zweiteXsteht für sich selbst, so dass das BRE „abcxdef
“ ist.Um das „Syndrom der schiefen Zahnstocher“ zu vermeiden, beachten Sie, dass die folgenden beiden regulären Ausdrücke gleichwertig sind:
/..\/..\/..\/Plumed.h/ \:../../../Plumed.h:
Beachten Sie, dass ich "äquivalent" gesagt habe.nichtrichtig. Das bringt mich zu meinem nächsten Punkt, der in jeder anderen Antwort fehlt:
Ein Punkt (
.
) in einem regulären Ausdruck steht fürbeliebiges Zeichen.Wenn Sie nur einen wörtlichen Punkt abgleichen möchten, können Sie Ihren Punkt entweder mit einem Backslash maskieren oder ihn wie in in eine Zeichenklasse einfügen
[.]
.Um nur wörtliche Punkte abzugleichen, sollte der reguläre Ausdruck also eher wie folgt lauten:
\:\.\./\.\./\.\./Plumed\.h:
Soviel zum Thema Vermeiden schief stehender Zahnstocher.
Sie können auch die vermutlich besser lesbare Form verwenden:
\:[.][.]/[.][.]/[.][.]/Plumed[.]h:
Der
c
Befehl ändert diegesamte Linie, nicht nur der Teil der Zeile, der mit dem regulären Ausdruck übereinstimmt.Verwenden Sie den
s
Befehl, um nur einen Teil einer Zeile zu ändern.Insbesondere
s
müssen Sie mit dem Befehl Ihr erstes Regex-Trennzeichen nicht maskieren (auch nicht, wenn es sich um ein ungewöhnliches Zeichen als Trennzeichen handelt), so wie Sie es tun, wenn Sie in einer Adresse ein alternatives Trennzeichen verwenden.In Bezug auf den
c
Befehl ist es außerdem wichtig zu wissen, dass das Einfügen des neuen Textes in dieselbe Zeile wie dasc\
eine GNU-Erweiterung ist und nicht portierbar.
Wenn Sie dies alles zusammenfassen, können Sie den s
Befehl folgendermaßen verwenden:
sed -i 's:"\.\./\.\./\.\./Plumed\.h":"/usr/local/include/Plumed.h":g' ../dist0.xvg
Oder, wenn Sie es noch deutlicher machen möchten, können Sie einen verankerten regulären Ausdruck und den c
Befehl „hange“ verwenden, um nur die ganze Zeile zu ändern:
sed -i '\:^#include "\.\./\.\./\.\./Plumed\.h"$:c\#include "/usr/local/include/Plumed.h"' ../dist0.xvg
Antwort2
/
Wenn Sie als Trennzeichen mit verwenden sed
, könnte eine Lösung wie folgt aussehen:
sed -i 's/..\/..\/..\/Plumed.h/\/usr\/local\/include\/Plumed.h/g' file
oder Sie können ein anderes Trennzeichen als verwenden /
, zum Beispiel :
:
sed -i 's:../../../Plumed.h:/usr/local/include/Plumed.h:g' file
Eine andere Möglichkeit mit awk
:
awk '{ gsub("../../../Plumed.h","/usr/local/include/Plumed.h"); print $0}' file
Antwort3
Dieser Befehl hat bei mir funktioniert:
sed -i 's#include "../../../Plumed.h"#include "/usr/local/include/Plumed.h"#g'
Antwort4
Verwenden Sie ein Ausrufezeichen, wenn der Text viele Schrägstriche enthält:
sed -e 's!../../../Plumed.h!/usr/local/include/Plumed.h!'