2

I would like to substitute a substring that contains an @ character with Perl as in the following sed command:

substitution='newusername@anotherwebsite.com'
sed 's/oldusername@website.com/'"${substitution}"'/g' <<< "The current e-mail address is oldusername@website.com"

At present wherever I use Perl instead of sed or awk I first replace \ with \\, / with \/, $ with \$ and @ with \@; e.g.

substitution='newusername@anotherwebsite.com'
substitution="${substitution//\\/\\\\}"
substitution="${substitution//\//\\/}"
substitution="${substitution//$/\\$}"
substitution="${substitution//@/\\@}"
perl -pe 's/oldusername\@website.com/'"${substitution}"'/g' <<< "The current e-mail address is oldusername@website.com"

I have read about using single quotation marks (as below based on sed/ perl with special characters (@)) but I was wondering if there is any other way to do this with forward slashes?

substitution='newusername@anotherwebsite.com'
perl -pe "s'oldusername@website.com'"${substitution}"'g" <<< "The current e-mail address is oldusername@website.com"

Also, are there special characters in Perl aside from $, @ and % (and why is there no need to escape %)?

gastone
  • 23
  • 3

1 Answers1

7

The cleanest way is to pass the values to Perl, as it can handle variables in substitution patterns and replacements correctly. Use single quotes so the shell's variable expansion doesn't interfere. You can use the -s option (explained in perlrun).

#!/bin/bash
pattern=oldusername@website.com
substitution=newusername@anotherwebsite.com
perl -spe 's/\Q$pat/$sub/g' -- -pat="$pattern" -sub="$substitution" <<< "The current e-mail address is oldusername@website.com"

or propagate the values to Perl via the environment.

pattern=oldusername@website.com
substitution=newusername@anotherwebsite.com
pat=$pattern sub=$substitution perl -pe 's/\Q$ENV{pat}/$ENV{sub}/g' <<< "The current e-mail address is oldusername@website.com"

Note that you need to assign the values before calling Perl or you need to export them in order to propagate them into the environment.

The \Q applies quotemeta to the pattern, i.e. it escapes all the special characters so that they are interpreted literally.

There's no need to backslash % as hashes aren't interpolated in double quotes or regexes.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • 3
    @TLP: What do you mean by "easier"? You need to `export` them or assign them before calling Perl, and you need to access the hash to get the values. – choroba Apr 16 '21 at 14:35
  • 1
    @TLP: Added the %ENV usage. – choroba Apr 16 '21 at 18:46
  • @TLP, for your [attention](https://www.tutorialspoint.com/perl/perl_variables.htm). and please have a good day further. :) – Gerhard Apr 16 '21 at 18:51
  • @TLP "_do you really need to `export` variables in bash before you can access them in `%ENV` inside Perl, even though they are defined in the same shell script?_" -- `export`-ing makes them "global" (environment) variables while mere assignment makes them "local," not propagated to child processes; see [docs](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html). But assigning _in the same statement_ works. In bash: `v=7; perl -wE'say $ENV{v}'` doesn't work (without the `;` it does). So needs to `export` unless it's always set and used in the same statement – zdim Apr 16 '21 at 21:21
  • @Gerhard I was going to link the same page to you, where it says "Hash variables". But I figured it was a side track and not worth pursuing. Yes, we can remove comments. – TLP Apr 16 '21 at 22:49