Wie kann ich die Variableninterpolation mit dem Perl-Substitutionsoperator deaktivieren?
Frage
Ich versuche, eine bestimmte Zeile in einer Textdatei auf VMS zu ersetzen.Normalerweise ist dies ein einfacher Einzeiler mit Perl.Allerdings stieß ich auf ein Problem, als die Ersatzseite ein Symbol war, das einen VMS-Pfad enthielt.Hier ist die Datei und was ich versucht habe:
Inhalt von file1.txt:
foo
bar
baz
quux
Versuch, die 3. Zeile zu ersetzen:
$ mysub = "disk$data1:[path.to]file.txt"
$ perl -pe "s/baz/''mysub'/" file1.txt
Ergibt die folgende Ausgabe:
foo
bar
disk:[path.to]file.txt
quux
Es sieht so aus, als ob Perl übereifrig war und das ersetzt hat $data1
Teil des Pfades mit dem Inhalt einer nicht existierenden Variablen (d. h. nichts).Das Ausführen mit dem Debugger hat dies bestätigt.Ich habe nicht geliefert /e
, also dachte ich, Perl sollte den Text einfach so ersetzen, wie er ist.Gibt es eine Möglichkeit, Perl dazu zu bringen, das zu tun?
(Beachten Sie auch, dass ich ein ähnliches Verhalten in der Linux-Befehlszeile reproduzieren kann.)
Lösung
Mit genau der richtigen Mischung aus Anführungszeichen und doppelten Anführungszeichen erreichen Sie Folgendes:
Wir erstellen eine enge Verkettung von „string“ + „Ersatzsymbol“ + „string“.Die beiden Zeichenfolgen in doppelten Anführungszeichen enthalten einfache Anführungszeichen für den Ersatz.Gekünstelt...Aber es funktioniert.
$ perl -pe "s'baz'"'mysub'"'" file1.txt
Das ist eine Lösung auf DCL-Ebene.
Verwenden Sie für eine Perl-Lösung die q()
Operator für eine nicht interpolierte Zeichenfolge und führen Sie diese aus.Fügen Sie das Symbol mithilfe einer einfachen DCL-Ersetzung in die Klammern ein.Das ist mein Favorit, weil es für mich (fast) Sinn ergibt und mit Zitaten nicht zu sehr verwirrend wirkt.
$ perl -pe "s/baz/q(''mysub')/e" file1.txt
Andere Tipps
Als Ruakh Beim Lesen meines Kommentars habe ich festgestellt, dass das Problem der Perl-Interpolation durch Zugriff auf gelöst werden kann %ENV
Hash, anstatt eine Shell-Variable zu verwenden:
perl -pwe "s/baz/$ENV{mysub}/" file1.txt
Hinzugefügt -w
weil ich nicht daran glaube, es nicht zu benutzen warnings
sogar in Einzeilern.
Ich habe seit Jahrzehnten nicht einmal ein VMS-System gesehen, aber ...deinem Siegel entkommen?
$ mysub = "disk\$data1:[path.to]file.txt"
oder vielleicht
$ mysub = "disk\\$data1:[path.to]file.txt"
?
Für sh
oder ein Derivat, das ich verwenden würde
perl -pe'BEGIN { $r = shift(@ARGV) } s/baz/$r/' "$mysub" file1.txt
Ansonsten muss man den Wert irgendwie verheimlichen mysub
in ein Perl-String-Literal umwandeln.Das wäre komplizierter.Finden Sie das Äquivalent für Ihre Shell.
Bearbeiten durch OP:
Ja, das funktioniert.Das VMS-Äquivalent ist
perl -pe "BEGIN { $r = shift(@ARGV) } s/baz/$r/" 'mysub' file1.txt
Du musst dem entkommen $
mit \$
.Andernfalls erkennt Perl eine Variablenreferenz und ersetzt die Zeichenfolge $data1
mit dem Inhalt von $data1
bevor der reguläre Ausdruck ausgewertet wird.Wie du es nicht definiert hast $data1
es ist natürlich leer.
Sie können den folgenden Code verwenden:
$ mysub='disk\$data1:[path.to]file.txt'
$ perl -pe 's/baz/'$mysub'/' FILE
foo
bar
disk$data1:[path.to]file.txt
quux
Sie könnten versuchen, einen logischen Namen anstelle eines DCL-Symbols zu verwenden:
$ define mysub "disk$data1:[path.to]file.txt"
$ $ perl -pe "s/baz/mysub/" file1.txt
Verwenden Sie sed.
Sed wird nicht versuchen zu interpolieren $data1
als Variable, also sollten Sie bekommen, was Sie wollen.
$ sed -e "s/baz/''mysub'/" file1.txt