LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   sed - testing multiline search and replace (https://www.linuxquestions.org/questions/programming-9/sed-testing-multiline-search-and-replace-806999/)

webhope 05-10-2010 01:11 PM

sed - testing multiline search and replace
 
Hi, I found a example how to do multiline search and replace. I try to make this working to my needs but with no success :-(

Step 1

I make a file with few lines:
one
two
five

Now I want to change it by the code:

Code:

sed -n '1h;1!H;${;g;s/one*five/one two three four five/g;p;}' test.lst
I run it but got this result:
one
two
five

no change. Somebody help?

Original code:
Code:

sed -n '1h;1!H;${;g;s/<h2.*</h2>/No title here/g;p;}' sample.php > sample-edited.php;

crts 05-10-2010 01:27 PM

Quote:

Originally Posted by webhope (Post 3963581)
Now I want to change it by the code:

Code:

sed -n '1h;1!H;${;g;s/one*five/one two three four five/g;p;}' test.lst

Hi,

I tried your code with one small change:
Code:

sed -n '1h;1!H;${;g;s/one.*five/one two three four five/g;p;}' test.lst
Notice the '.' before '*'. It worked for me.
Hope this helps.

webhope 05-10-2010 01:40 PM

Quote:

Originally Posted by crts (Post 3963602)
I tried your code with one small change:

Notice the '.' before '*'. It worked for me.
Hope this helps.

Ooops. This was foolish. But next step. I want to use variables to get pattern there:

Step 2

Code:

clear
search="one.*five"
replace="one two three four five"
sed -n "1h;1!H;${;g;s/"$search"/"$replace"/g;p;}" /boot/grub/test.lst | head -n 4

This returns error of token near "("
How should I to correct it to have regular syntax?

crts 05-10-2010 02:26 PM

Quote:

Originally Posted by webhope (Post 3963619)
Ooops. This was foolish. But next step. I want to use variables to get pattern there:

Step 2.

Code:

clear
search="one.*five"
replace="one two three four five"
sed -n "1h;1!H;${;g;s/"$search"/"$replace"/g;p;}" /boot/grub/test.lst | head -n 4

This returns error of token near "("
How should I to correct it to have regular syntax?

Try this
Code:

sed -n "1h;1! H;$ {;g;s/$search/$replace/g;p;}" /boot/grub/test.lst |head -n 4
Notice the extra space at '1! H' and '$ {'. You also just need one enclosing pair of double-quotes (" ").

webhope 05-10-2010 02:40 PM

Quote:

Originally Posted by crts (Post 3963684)
Try this
Code:

sed -n "1h;1! H;$ {;g;s/$search/$replace/g;p;}" /boot/grub/test.lst |head -n 4
Notice the extra space at '1! H' and '$ {'. You also just need one enclosing pair of double-quotes (" ").

Yeah! The extra space before H and { works! Thanx

I am gonna to try it all in loop with an array.

Here it is:

Code:

search="one.*five"
content=("one two three four five" "bla bla bla bla" "na na na na")
n=0
sed -n "1h;1! H;$ {;g;s/$block/${content[$n]}/g;p;}" /boot/grub/test.lst | head -n 4

Returns some error

crts 05-10-2010 03:59 PM

Quote:

Originally Posted by webhope (Post 3963703)
Yeah! The extra space before H and { works! Thanx

I am gonna to try it all in loop with an array.

Here it is:

Code:

search="one.*five"
content=("one two three four five" "bla bla bla bla" "na na na na")
n=0
sed -n "1h;1! H;$ {;g;s/$block/${content[$n]}/g;p;}" /boot/grub/test.lst | head -n 4

Returns some error

If the error is
Code:

sed: -e expression #1, char 0: no previous regular expression
then this is because there is no variable named 'block'.
Change your code either to
Code:

search="one.*five"
content=("one two three four five" "bla bla bla bla" "na na na na")
n=0
sed -n "1h;1! H;$ {;g;s/$search/${content[$n]}/g;p;}" /boot/grub/test.lst | head -n 4

or
Code:

block="one.*five"
content=("one two three four five" "bla bla bla bla" "na na na na")
n=0
sed -n "1h;1! H;$ {;g;s/$block/${content[$n]}/g;p;}" /boot/grub/test.lst | head -n 4


webhope 05-10-2010 04:46 PM

Quote:

Originally Posted by crts (Post 3963792)
If the error is
Code:

sed: -e expression #1, char 0: no previous regular expression
then this is because there is no variable named 'block'.

Oh, feathery. I thought that the syntax is wrong. But the original code, which I try to make working, still doesn't work. So I will show you the final part.

Code:

while [[ $n -lt ${#content[@]} ]]; do
    n=$((n+1));
    original_block=$(echo ${original_content[$n]} | awk 'BEGIN { FS="\n"; RS="";}  {b = gensub(/([\]*+/()])/, "\\\\&", "g"); print b }')
  set -x
  sed -n "1h;1! H;$ {;g;s/$original_block/${content[$n]}/g;p;}" /boot/grub/test.lst
done;

$original_content - is array with blocks of original code of menu.lst
$content - is array with blocks of code that was changed
$original_block - is one item (block) from $original_content[$n]
$content[$n] - block that was changed

This report I have:
Code:

+ sed -n '1h;1! H;$ {;g;s/title Sata Mandriva kernel \(hd0,2\)\/boot\/vmlinuz BOOT_IMAGE=linux root=(hd0,2)  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788 initrd \(hd0,2\)\/boot\/initrd.img/title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788
initrd (hd0,2)/boot/initrd.img/g;p;}' /boot/grub/test.lst
sed: -e výraz č.*1, znak 258: neukončený příkaz „s“

That is 3 lines of search:
Code:

title Sata Mandriva
kernel \(hd0,2\)\/boot\/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788
initrd \(hd0,2\)\/boot\/initrd.img

And 3 lines of replacement:
Code:

title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=(hd0,2)  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788
initrd (hd0,2)/boot/initrd.img/g;p;}' /boot/grub/test.lst

Code:

sed: -e expression #1, char 258: "neukončený příkaz"(not enclosed command) „s“
Do you know what is wrong with the "s" command?

grail 05-10-2010 08:21 PM

Quote:

+ sed -n '1h;1! H;$ {;g;s/title Sata Mandriva kernel \(hd0,2\)\/boot\/vmlinuz BOOT_IMAGE=linux root=(hd0,2) resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788 initrd \(hd0,2\)\/boot\/initrd.img/title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788
initrd (hd0,2)/boot/initrd.img/g;p;}' /boot/grub/test.lst
sed: -e výraz č.*1, znak 258: neukončený příkaz „s“
One would say that all the unescaped slashes (/) in the replacement would be the issue.

webhope 05-11-2010 02:38 AM

Quote:

Originally Posted by grail (Post 3964031)
One would say that all the unescaped slashes (/) in the replacement would be the issue.

I have changed pattern for search only. Drom replacement do I need to escape all chars like * / \ (), or only the slashes?

crts 05-11-2010 02:51 AM

Quote:

Originally Posted by webhope (Post 3964326)
I have changed pattern for search only. Drom replacement do I need to escape all chars like * / \ (), or only the slashes?

That depends. If you don't use extended regular expressions you don't have to escape the braces when they are supposed to be part of the regular expression. You don't even have to escape the slash '/' if you choose another delimiter in the substitution command, e.g.
Code:

sed -e 's@expression1@expression2@' file

webhope 05-11-2010 04:25 AM

Code:

sed -n '1h;1! H;$ {;g;s@title Sata Mandriva kernel \(hd0,2\)\/boot\/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788 initrd \(hd0,2\)\/boot\/initrd.img@title Sata Mandriva
kernel (hd0,2)/boot/vmlinuz BOOT_IMAGE=linux root=UUID=eab515e9-bc3e-4024-9f01-55fddaa0fb1c  resume=UUID=e12487ff-6d6f-44c4-9e03-33f545b3b798 splash=silent vga=788
initrd (hd0,2)/boot/initrd.img@g;p;}' /boot/grub/test.lst
sed: -e expression n.*1, char 258: command „s“ not closed

Could be the problem here? There are two breaklines:
after "@title Sata Mandriva"
and after "splash=silent vga=788"

webhope 05-13-2010 02:21 PM

So I found I have to escape all New line characters (as I call breakline).

I used this code to escape some characters and breaklines on Search part and Replacement part:

Code:

echo "${content[1]}" | awk '{b = gensub(/([\]*+/])/, "\\\\&", "g"); printf "%s\\n",b }'
Other words: I found that Search part and Replacement part must not have new lines characters. Because of the delimiter for was a slash: // and the search part contained slashes, there was error. Then I replaced this delimiter to ampersand @@, and sed works now.


All times are GMT -5. The time now is 06:38 PM.