2

I have this line that I want to use sed / perl on:

perl -pi -e  "s/password/p@ssw0rd/g" <file_name>

How can I make sed/perl ignore special characters, I tried adding back slash before special characters, but maybe I got it wrong, can some one show me an example?

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • For sed, the only special character in the substitution string is `&`. `@` shouldn't be a problem. – Benjamin W. May 30 '18 at 17:35
  • 2
    Welcome to SO, kindly post 3 simple things in your post, 1- sample of input, 2- sample of output 3rd- your efforts to solve the problem in CODE TAGS please. – RavinderSingh13 May 30 '18 at 17:35
  • Double quotes for the code string? Been a while I dabbled on a unix, but I thought single quotes were prefered, so that bash wouldn't change stuff in the string. – LukStorms May 30 '18 at 17:46
  • Can we do the same if we are passing the values as parameter (variable) ? CURRENTVAULE=password NEWVALUE=p@ssW0rd perl -pi -e 's/$CURRENTVALUE/$NEWVALUE/g' filename sed -i '' -e 's/$CURRENTVALUE/$NEWVALUE/g' – Sankareswar May 31 '18 at 13:41

2 Answers2

4

The @ is only special to Perl, not sed, so you could simply use sed in this case:

sed -i -e 's/password/p@ssw0rd/g' filename     # GNU sed
sed -i '' -e 's/password/p@ssw0rd/g' filename  # BSD sed

You should get in the habit of using single-quotes when passing code to commands from the shell, because then none of the code is modified by the shell before the command sees it. If you do that, then backslashing the at sign will work for Perl:

perl -pi -e  's/password/p\@ssw0rd/g' filename

You can also use single-quote as the delimiter in the substitution expression, which causes the contained expressions to be interpreted literally with no expansion; that's easier if you go back to double-quotes in the shell:

perl -pi -e "s'password'p@ssw0rd'g" filename

But if you might need to worry about shell expansion in there, you need to both quote the string of code in the shell with single quotes and use single quotes as the delimiter, which is awkward enough that you're probably better off just going with the backslash on the at sign:

perl -pi -e  's'\''password'\''p@ssw0rd'\''g' filename # POSIX shell
perl -pi -e  $'s\'password\'p@ssw0rd\'g' filename      # bash/ksh/zsh ANSI string

To answer your question in the comments, if you want to make the old and new strings dynamic arguments passed as envariables, they would be $ENV{varname} rather than just $varname in Perl, and you have to treat them differently. You no longer have to worry about interpolation on the replacement value (since you want exactly one level of it), but you do have to worry about special regex characters on the pattern side, which means you need to put \Q...\E around what you're looking for:

CURRENTVALUE=password NEWVALUE=p@ssw0rd perl -pi -e 's/\Q$ENV{CURRENTVALUE}\E/$ENV{NEWVALUE}/g' filename

... that is, unless you want the value of $CURRENTVALUE to be able to be a regex instead of just a literal string. But you have to pick one.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
4

In perl @ denotes an array variable. Since the right-hand side of s/// allows variable interpolation, s/password/p@ssw0rd/ is looking for the "@ssw0rd" variable.

An example:

$ perl -pe '@ssw0rd=("a","b","c"); s/password/p@ssw0rd/g' <<INPUT
> this is my password here
> INPUT
this is my pa b c here

and without defining the array variable, an empty string is substituted:

$ perl -pi -e 's/password/p@ssw0rd/g' <<INPUT
> this is my password here
> INPUT
this is my p here

Documentation from perldoc perlop in Quote and Quote-like Operators:

For constructs that do interpolate, variables beginning with "$" or "@" are interpolated. Subscripted variables such as $a[3] or $href->{key}[0] are also interpolated, as are array and hash slices. But method calls such as $obj->meth are not.

Interpolating an array or slice interpolates the elements in order, separated by the value of $", so is equivalent to interpolating join $", @array. "Punctuation" arrays such as @* are only interpolated if the name is enclosed in braces @{*}, but special arrays @_, @+, and @- are interpolated, even without braces.

Therefore, in the replacement part of s/// you have to take special care of $ and @

glenn jackman
  • 238,783
  • 38
  • 220
  • 352