I have the following perl search and replace :
With Escapes :
perl -pi -w -e 's/ onclick=\"img=document.getElementById(\'img_1\')\; img.style.display = (img.style.display == \'none\' ? \'block\' : \'none\');return false"//' test.html
Without Escapes :
perl -pi -w -e 's/ onclick="img=document.getElementById('img_1'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false"//' test.html
My objective is to replace onclick="img=document.getElementById('img_1'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false"
with nothing in the file test.html
. What am I messing up?
I keep on getting the error : -sh: syntax error near unexpected token
)'` which I cannot help but feel is because of some stupid escaping on my part. Please help me out.
[ You didn't specify for which shell you are building the command. I'm going to assume sh
or bash
. ]
Problem #1: Converting text into a regex pattern
Many characters have a special meaning in regex patterns. Among those you used, (
, )
, .
and ?
are special. These need to be escaped.
If you want to match
onclick="img=document.getElementById('img_1'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false"
You need to use the pattern
onclick="img=document\.getElementById\('img_1'\); img\.style\.display = \(img\.style\.display == 'none' \? 'block' : 'none'\);return false"
So your Perl code is
s/onclick="img=document\.getElementById\('img_1'\); img\.style\.display = \(img\.style\.display == 'none' \? 'block' : 'none'\);return false"//
Problem #2: Converting text (a Perl program) into a shell literal
This is the problem you asked about.
Sections quoted by single quotes ("'
") end at the next single quote (unconditionally), so the following is wrong:
echo 'foo\'bar' # Third "'" isn't matched.
If you wanted to output "foo'bar
", you could use
echo 'foo'\''bar' # Concatenation of "foo", "'" and "bar".
foo
and bar
are quoted by single quotes, and the single quote is escaped using \
. \
works here because it's outside of single quotes.
So, the lesson is basically use '\''
instead of '
inside single quotes.
you want to pass the following program to Perl:
s/onclick="img=document\.getElementById\('img_1'\); img\.style\.display = \(img\.style\.display == 'none' \? 'block' : 'none'\);return false"//
To do so, you'll need to create a shell literal that produces the correct argument, meaning we want to surround the whole with single quotes and escape the existing single quotes. We get the following:
's/onclick="img=document\.getElementById\('\''img_1'\''\); img\.style\.display = \(img\.style\.display == '\''none'\'' \? '\''block'\'' : '\''none'\''\);return false"//'
As such, the entire command would be
perl -i -wpe's/onclick="img=document\.getElementById\('\''img_1'\''\); img\.style\.display = \(img\.style\.display == '\''none'\'' \? '\''block'\'' : '\''none'\''\);return false"//' test.html
Using the next:
perl -lnE 'say quotemeta $_'
and feed it with your plain input:
onclick="img=document.getElementById('img_1'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false"
you will get:
onclick\=\"img\=document\.getElementById\(\'img_1\'\)\;\ img\.style\.display\ \=\ \(img\.style\.display\ \=\=\ \'none\'\ \?\ \'block\'\ \:\ \'none\'\)\;return\ false\"
So using it:
perl -i -pe "s/onclick\=\"img\=document\.getElementById\(\'img_1\'\)\;\ img\.style\.display\ \=\ \(img\.style\.display\ \=\=\ \'none\'\ \?\ \'block\'\ \:\ \'none\'\)\;return\ false\"//"
should work.
Some things are easier when you don't use a one-liner. Less things to escape, and not as fragile.
use strict;
use warnings;
my $literal_string = q{ onclick="img=document.getElementById('img_1'); img.style.display = (img.style.display == 'none' ? 'block' : 'none');return false"};
while (<>) {
s/\Q$literal_string//;
print;
}
Then execute the script:
perl -i thescript.pl test.html