Comment puis-je désactiver l'interpolation de variables avec l'opérateur de substitution Perl ?
Question
J'essaie de remplacer une ligne particulière dans un fichier texte sur VMS.Normalement, il s'agit d'un simple one-liner avec Perl.Mais j'ai rencontré un problème lorsque le côté de remplacement était un symbole contenant un chemin VMS.Voici le fichier et ce que j'ai essayé :
Contenu du fichier1.txt :
foo
bar
baz
quux
Tentative de remplacement de la 3ème ligne :
$ mysub = "disk$data1:[path.to]file.txt"
$ perl -pe "s/baz/''mysub'/" file1.txt
Donne le résultat suivant :
foo
bar
disk:[path.to]file.txt
quux
Il semble que Perl ait été trop enthousiaste et ait remplacé le $data1
partie du chemin avec le contenu d'une variable inexistante (c'est-à-dire rien).L'exécution avec le débogueur l'a confirmé.je n'ai pas fourni /e
, j'ai donc pensé que Perl devrait simplement remplacer le texte tel quel.Existe-t-il un moyen pour que Perl fasse cela ?
(Notez également que je peux reproduire un comportement similaire sur la ligne de commande Linux.)
La solution
Avec juste la bonne combinaison de guillemets et de guillemets doubles, vous pouvez y arriver :
Nous créons une concaténation étroite de « chaîne » + « symbole de remplacement » + « chaîne ».Les deux chaînes entre guillemets doubles contiennent des guillemets simples pour le substitut.Artificiel...mais ça marche.
$ perl -pe "s'baz'"'mysub'"'" file1.txt
C'est une solution de niveau DCL.
Pour une solution Perl, utilisez le q()
opérateur pour une chaîne non interpolée et exécutez-le.Insérez le symbole dans les parenthèses en utilisant une simple substitution DCL.C'est mon préféré car cela a (presque) du sens pour moi et ne devient pas trop déroutant avec les citations.
$ perl -pe "s/baz/q(''mysub')/e" file1.txt
Autres conseils
Comme ruakh découvert en lisant mon commentaire, le problème de l'interpolation Perl peut être résolu en accédant au %ENV
hachage, plutôt que d'utiliser une variable shell :
perl -pwe "s/baz/$ENV{mysub}/" file1.txt
Ajoutée -w
parce que je ne crois pas qu'il faille ne pas utiliser warnings
même en one-liners.
Je n'ai même pas vu de système VMS depuis des décennies, mais...échapper à ton sceau ?
$ mysub = "disk\$data1:[path.to]file.txt"
ou peut-être
$ mysub = "disk\\$data1:[path.to]file.txt"
?
Pour sh
ou un dérivé, j'utiliserais
perl -pe'BEGIN { $r = shift(@ARGV) } s/baz/$r/' "$mysub" file1.txt
Sinon, vous devez d'une manière ou d'une autre dissimuler la valeur de mysub
en une chaîne Perl littérale.Ce serait plus compliqué.Trouvez l'équivalent pour votre shell.
Modifier par OP :
Oui, cela fonctionne.L'équivalent VMS est
perl -pe "BEGIN { $r = shift(@ARGV) } s/baz/$r/" 'mysub' file1.txt
Il faut échapper au $
avec \$
.Sinon, Perl voit une référence à une variable et remplace la chaîne $data1
avec le contenu de $data1
avant que l'expression régulière soit évaluée.Comme tu ne l'as pas défini $data1
il est bien sûr vide.
Vous pouvez utiliser le code suivant :
$ mysub='disk\$data1:[path.to]file.txt'
$ perl -pe 's/baz/'$mysub'/' FILE
foo
bar
disk$data1:[path.to]file.txt
quux
Vous pouvez essayer d'utiliser un nom logique au lieu d'un symbole DCL :
$ define mysub "disk$data1:[path.to]file.txt"
$ $ perl -pe "s/baz/mysub/" file1.txt
Utilisez sed.
Sed n'essaiera pas d'interpoler $data1
en tant que variable, vous devriez donc obtenir ce que vous voulez.
$ sed -e "s/baz/''mysub'/" file1.txt