What does this perl replace string do? - regex

I have no idea what is going on here ... I am trying to manually do this rather than have Perl do it.
my $replace_string
= "s/typedef struct WebFontDescription WebFontDescription/struct WebFontDescription/g";
print $fh "perl -p -i -e \""
. $replace_string
. "\" \""
. $idl_filename
. "\"\r\n";
$replace_string
= "s/\(WebFontDescription\\* webFontDescription/\(struct WebFontDescription\\* webFontDescription/g";
print $fh "perl -p -i -e \""
. $replace_string
. "\" \""
. $idl_filename
. "\"\r\n";
I see that it looks for a string
typedef struct WebFontDescription WebFontDescription
and then replaces it with
s/\(WebFontDescription\\* webFontDescription/\(struct WebFontDescription\\* webFontDescription/g
but how do you replace a regex with a regex? That doesn't make any sense...

It creates the following pair of shell commands:
perl -p -i -e "s/typedef struct WebFontDescription WebFontDescription/struct WebFontDescription/g" "file"
perl -p -i -e "s/(WebFontDescription\* webFontDescription/(struct WebFontDescription\* webFontDescription/g" "file"
The first one replaces every instance of
typedef struct WebFontDescription WebFontDescription
with
struct WebFontDescription
The second doesn't do anything but throw an error message because it doesn't compile. (Unmatched (.)

Related

perl regex doesn't match and include next line [duplicate]

I'm trying to use perl (v5.14.2) via a bash shell (GNU Bash-4.2) in Kubuntu (GNU/Linux) to search and replace a string that includes a newline character, but I'm not succeeding yet.
Here's the text file I'm searching:
<!-- filename: prac1.html -->
hello
kitty
blah blah blah
When I use a text editor's (Kate's) search-and-replace functionality or when I use a regex tester (http://regexpal.com/), I can easily get this regex to work:
hello\nkitty
But when using perl in the command line, none of the following commands have worked:
perl -p -i -e 's,hello\nkitty,newtext,' prac1.html
perl -p -i -e 's,hello.kitty,newtext,s' prac1.html
perl -p -i -e 's,hello.*kitty,newtext,s' prac1.html
perl -p -i -e 's,hello[\S\s]kitty,newtext,' prac1.html
perl -p -i -e 's,hello[\S\s]*kitty,newtext,' prac1.html
Actually, I got desperate and tried many other patterns, including all of these (different permutations in the "single-line" and "multi-line" modes):
perl -p -i -e 's,hello\nkitty,newtext,' prac1.html
perl -p -i -e 's,hello.kitty,newtext,' prac1.html
perl -p -i -e 's,hello\nkitty,newtext,s' prac1.html
perl -p -i -e 's,hello.kitty,newtext,s' prac1.html
perl -p -i -e 's,hello\nkitty,newtext,m' prac1.html
perl -p -i -e 's,hello.kitty,newtext,m' prac1.html
perl -p -i -e 's,hello\nkitty,newtext,ms' prac1.html
perl -p -i -e 's,hello.kitty,newtext,ms' prac1.html
perl -p -i -e 's,hello[\S\s]kitty,newtext,' prac1.html
perl -p -i -e 's,hello[\S\s]*kitty,newtext,' prac1.html
perl -p -i -e 's,hello$[\S\s]^kitty,newtext,' prac1.html
perl -p -i -e 's,hello$[\S\s]*^kitty,newtext,' prac1.html
perl -p -i -e 's,hello[\S\s]kitty,newtext,s' prac1.html
perl -p -i -e 's,hello[\S\s]*kitty,newtext,s' prac1.html
perl -p -i -e 's,hello$[\S\s]^kitty,newtext,s' prac1.html
perl -p -i -e 's,hello$[\S\s]*^kitty,newtext,s' prac1.html
perl -p -i -e 's,hello[\S\s]kitty,newtext,m' prac1.html
perl -p -i -e 's,hello[\S\s]*kitty,newtext,m' prac1.html
perl -p -i -e 's,hello$[\S\s]^kitty,newtext,m' prac1.html
perl -p -i -e 's,hello$[\S\s]*^kitty,newtext,m' prac1.html
perl -p -i -e 's,hello[\S\s]kitty,newtext,ms' prac1.html
perl -p -i -e 's,hello[\S\s]*kitty,newtext,ms' prac1.html
perl -p -i -e 's,hello$[\S\s]^kitty,newtext,ms' prac1.html
perl -p -i -e 's,hello$[\S\s]*^kitty,newtext,ms' prac1.html
(I also tried using \r \r\n \R \f \D etc., and global mode as well.)
Can anyone spot the issue or suggest a solution?
Try doing this, I make this possible by modifying the input record separator (a newline by default) :
perl -i -p00e 's,hello\nkitty,newtext,' prac1.html
from perldoc perlrun :
-0[octal/hexadecimal]
specifies the input record separator ($/ ) as an octal or hexadecimal
number. If there are no digits, the null character is the separator.
Other switches may precede or follow the digits. For example, if you
have a version of find which can print filenames terminated by the
null character, you can say this:
find . -name '*.orig' -print0 | perl -n0e unlink
The special value 00 will cause Perl to slurp files in paragraph mode.
Any value 0400 or above will cause Perl to slurp files whole, but by
convention the value 0777 is the one normally used for this purpose.
The problem is that "-p" has already implicitly wrapped this loop around your "-e", and the "<>" is splitting the input into lines, so your regexp never gets a chance to see more than one line.
LINE:
while (<>) {
... # your program goes here
} continue {
print or die "-p destination: $!\n";
}
See the perlrun manpage for more information.

String not containing whitespace followed by digit

I am trying to come up with a regex that returns a certain jpeg filename in a folder not containing a whitespace followed by digit at the end of the filename, e.g., 002504_GDG_EN_160902.jpeg would be fine, 002504_GDG_EN_160902 5.jpeg not.
My best guess so far is, with $file being the filename without the suffix and any number (e.g., 002504_GDG_EN_160902):
test=$(ls *.jpeg | sort | grep $file | grep -v '.*\s\d\.jpeg')
This works fine for the the above mentioned example, but somehow not for cases where $file is 2016_MUC-Werk_[B_DGF_LA_LZ_R]_FG-8_all_160926. Probably because of the brackets and/or minuses.
No need to use ls and grep.
Using extglob:
shopt -s nullglob
shopt -s extglob
printf "%s\n" +([^[:blank:]]).jpeg
002504_GDG_EN_160902.jpeg
Or to store matching filenames in an array:
files=(+([^[:blank:]]).jpeg)
+([^[:blank:]]).jpeg will match filenames with 1 or more non-space characters followed by .jpeg
Sample data:
ls -1
002504_GDG_EN_16090 2.jpeg
002504_GDG_EN_160901 32.jpeg
002504_GDG_EN_1609012.jpeg
002504_GDG_EN_1609013.jpeg
2016_MUC-Werk_[B_DGF_LA_LZ_R]_FG-8_all_160926
solution using array:
array=(*)
printf "%s\n" "${array[#]}" |grep -Pv '\d\s\d.*(.jpeg|$)'
002504_GDG_EN_1609012.jpeg
002504_GDG_EN_1609013.jpeg
2016_MUC-Werk_[B_DGF_LA_LZ_R]_FG-8_all_160926
to store it in any variable:
var=$(printf "%s\n" "${array[#]}" |grep -Pv '\d\s\d.*(.jpeg|$)')
echo "$var"
002504_GDG_EN_1609012.jpeg
002504_GDG_EN_1609013.jpeg
2016_MUC-Werk_[B_DGF_LA_LZ_R]_FG-8_all_160926

Why the following variations of s/g from command line are wrong?

I have a small file as follows:
$ cat text.txt
vacation
cat
This is a test
This command substitutes all occurrences of cat to CAT correctly as I wanted:
$ perl -p -i -e '
s/cat/CAT/g;
' text.txt
But why the following two mess the file up?
The following deletes the contents of the file
$ perl -n -i -e '
$var = $_;
$var =~ s/cat/CAT/g;
' text.txt
And this one just does not do the substitution correctly
$ perl -p -i -e '
$var = $_;
$var =~ s/cat/CAT/g;
' text.txt
$ cat text.txt
cation
cat
This is a test
Why? What am I messing up here?
-p prints out each line automatically (the contents of $_, which contains the current line's contents), which re-populates the file (due to the -i flag in use), where -n loops over the file like -p does, but it doesn't automatically print. You have to do that yourself, otherwise it just overwrites the file with nothing. The -n flag allows you to skip over lines that you don't want to re-insert into the original file (amongst other things), whereby with -p, you'd have to use conditional statements along with next() etc. to achieve the same result.
perl -n -i -e '
$var = $_;
$var =~ s/cat/CAT/g;
print $var;
' text.txt
See perlrun.
In your last example, -p will only automatically print $_ (the original, unmodified line). It doesn't auto-print $var at all, so in that case, you'd have to print $var like in the example above, but then you'd get both the original line, and the modified one printed to the file.
You're better off not assigning $_ to anything if all you're doing is overwriting a file. Just use it as is. eg. (same as your first example):
perl -p -i -e '
s/cat/CAT/g;
' text.txt

Need to use grep to find a string within a file

Im using a shell script to get a file using wget and search it for a pattern. My shell script is as follows:
#Execute commands one by one
while read line
do
STARTTIME=$(($(date +%s%N)/1000000))
line2=$(wget -q --post-data "$line" -O PHPFiles/test.php http://localhost:1234/XSS/XSS2/test.php)
ENDTIME=$(($(date +%s%N)/1000000))
GAP=$(($ENDTIME-$STARTTIME))
DIFF=$(($DIFF+($ENDTIME-$STARTTIME)))
echo "Time Taken "$GAP
finalSearchLine1="${line/&name2=/ }"
finalSearchLine2="${finalSearchLine1/name=/}"
echo "$finalSearchLine2"
if grep -q -F "$finalSeachLine2" -a PHPFiles/test.php;
then
echo found
success=$((success+1))
else
echo not found
failure=$((failure+1))
fi
rm PHPFiles/test.php
done < $1
echo "***************"
echo "Success "$success
echo "Failure "$failure
echo "Total Time "$DIFF
echo "Average Time "$((DIFF/(success+failure)))
However, I'm having trouble with the grep command. Sometimes, the data $finalSearchLine2 contains quotes such as:
<script >alert("XSS"); </script>
This seem to cause trouble with the grep command. For the if statement, I always seem to get the result as found even when there is no matching pattern in the $finalSearchLine2 variable. I dont know if its possible to use escape strings within the variable for grep. Can anyone suggest a possible solution for this?
Grep needs double quotes to be escaped like this \"
So as a first solution you could try:
temp_variable=$(sed 's/"/\\"/g' <<< $temp)
if grep -q -F "$temp_variable" -a /PHPFiles/test.php;
So you first escape the double quotes with sed and you store the result in temp_variable. Then you use temp_variable in grep.

Replacing string in file with perl

I have a list of about 10 servers that I would like to change a string in all 10 servers.
I have written a script that looks at the file and with a loop and should use perl -i -pe to change the line /opt/nimsoft/bin/niminit "" "start" to #/opt/nimsoft/bin/niminit "" "start" (add a # to comment out)
oldstring = /opt/nimsoft/bin/niminit "" "start"
newstring = #/opt/nimsoft/bin/niminit "" "start"
I am having trouble escaping the /, I have tried \ and \Q and \E. Any ideas?
for i in `cat $file`
do
echo "Disable application on startup"
oldstring=start /opt/nimsoft/bin/niminit "" "start"
newstring=#start /opt/nimsoft/bin/niminit "" "start"
ssh -t $i sudo perl -p -i -e 's/oldstring/newstring/g' /etc/rc.tcpip
# /etc/rc.tcpip:start /opt/nimsoft/bin/niminit "" "start"
echo "==============================================="
done
If you use s{}{} instead of s///, you won't have to worry about escaping the forward slashes.
The following adds a comment before the string that you wanted to match if it isn't already commented:
perl -i -pe 's{(?<!#)(?=start /opt/nimsoft/bin/niminit "" "start")}{#}' /etc/rc.tcpip
Perl will permit the use of delimiters other than /. You might try ~ or { } pairs. Also, sed might be easier to use than a Perl script.