Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I escape special characters for a substitution in a Perl one-liner?

Tags:

perl

Is there some way to replace a string such as @or * or ? or & without needing to put a "\" before it?

Example:

perl -pe 'next if /^#/; s/\@d\&/new_value/ if /param5/' test

In this example I need to replace a @d& with new_value but the old value might contain any character, how do I escape only the characters that need to be escaped?

like image 422
yael Avatar asked May 27 '10 15:05

yael


People also ask

How do you escape a special character in Perl?

The backslash is the escape character and is used to make use of escape sequences. When there is a need to insert the escape character in an interpolated string, the same backslash is used, to escape the substitution of escape character with ” (blank). This allows the use of escape character in the interpolated string.

How do I escape a single quote in Perl?

This works because in Perl, the s/.../.../ notation supports backslash-escapes. \x27 is a hexadecimal escape ( ' being U+0027). Show activity on this post. This ends the quoted part, escapes a single quote as it would appear outside of quotes, and then begins the quoting again.


2 Answers

As discussed at perldoc perlre:

...Today it is more common to use the quotemeta() function or the "\Q" metaquoting escape sequence to disable all metacharacters' special meanings like this:

/$unquoted\Q$quoted\E$unquoted/

Beware that if you put literal backslashes (those not inside interpolated variables) between "\Q" and "\E", double-quotish backslash interpolation may lead to confusing results. If you need to use literal backslashes within "\Q...\E", consult "Gory details of parsing quoted constructs" in perlop.

You can also use a ' as the delimiter in the s/// operation to make everything be parsed literally:

my $text = '@';
$text =~ s'@'1';
print $text;

In your example, you can do (note the single quotes):

perl -pe 's/\b\Q@f&\E\b/new_value/g if m/param5/ and not /^ *#/'
like image 175
Ether Avatar answered Sep 30 '22 10:09

Ether


You have several problems:

  1. You are using \b incorrectly
  2. You are replacing code with shell variables
  3. You need to quote metacharacters

From perldoc perlre

A word boundary ("\b") is a spot between two characters that has a "\w" on one side of it

Neither of the characters @ or & are \w characters. So your match is guaranteed to fail. You may want to use something like s/(^|\s)\@d\&(\s|$)/${1}new text$2/

(^|\s) says to match either the start of the string (^)or a whitespace character (\s).

(\s|$) says to match either the end of the string ($) or a whitespace character (\s).

To solve the second problem, you should use %ENV.

To solve the third problem, you should use the \Q and \E escape sequences to escape the value in $ENV{a}.

Putting it all together we get:

#!/bin/bash

export a='@d&'
export b='new text'

echo 'param5 @d&' | 
    perl -pe 'next if /^#/; s/(^|\s)\Q$ENV{a}\E(\s|$)/$1$ENV{b}$2/ if /param5/' 

Which prints

param5 new text
like image 22
Chas. Owens Avatar answered Sep 30 '22 10:09

Chas. Owens