Say like I have hi() everywhere in a shell script and I would like to replace only a hi() to hi(20) right under the line "#modify only the hi() below this line".

Is there anyway that I can locate the line "#modify only the hi() below this line" and then do a replacement on the line right under the cursor?

example:

#!/bin/sh
hi()
some other code
#modify only the hi() below this line
hi()   [B]---> this is the hi() i want to modify[/B]
hi()
other code
hi()
other code
hi()

or if there is any other better approach? thanks

Hello k2k!

This is a perfect case for SED!

You can use something like this to match the two lines with '#modify...' and 'hi()', and replace just that (those?) instances. Some googling will show you some examples that are close, but I didn't find anything that fit your issue exactly, so here's what I tried, and the result:

Here's the simple sed statement:

sed '/#modify/,/hi()/ s/^hi()/hi(20)/'

Here's the result:

-> sed '/#modify/,/hi()/ s/^hi()/hi(20)/' tmp.txt
hi()
some other code
#modify only the hi() below this line
hi(20)   ---> this is the hi() i want to modify
hi()
other code
hi()
other code
hi()

Here's a breakdown of the sed command:

sed '
/#modify/,/hi()/  <- Here we look at only the line with #modify and the next one with hi()
s/^hi()/hi(20)/    <- Here we replace the hi() at the beginning of the line with hi(20)
' tmp.txt

I hope this helps!

Edited 5 Years Ago by JeoSaurus: pasted same command with two different formats...

sed '/#modify/,/hi()/ s/^hi()/hi(20)/' tmp.txt

ummm, you did gave me some good hints. however, the shell complains about the " , "
maybe syntax is a bit off?

by the way, can I match more than 2 lines?

sed '/line1/,/line2/,/line3/ s/^line2/line2change/'

something like this?

never mind, my bad that i forgot to redirect it to a new file. still not sure about matching more than 2 lines.

one problem is that it will modify all the ^hi() to hi(20) instead of modifying only line 6 hi() I need. it doesn't look like the 2 line matching works.. = (

Well this script will only match those two lines. I don't think you can specify three patterns like that. I'm not exactly sure what you're asking there. Could you give us an example?

Also, are you saying that the the 'sed' line I posted above matches more than just the single hi() after the #modify line?

It might be a shell interpretation thing... Try with brackets around the search/replace string like this: sed '/#modify/,/hi()/ {s/^hi()/hi(20)/}'

sed '/#modify/,/hi()/ {s/^hi()/hi(20)/}'

May I ask what does {s/^hi()/hi(20)/} the carat do?

It actually matches and replaces all the hi() if it starts at the beginning of the line

Sure! The carat matches the beginning of the line, so in the case of these two lines:

#modify only the hi() below this line
hi() ---> this is the hi() i want to modify

...only the hi() at the beginning of the line will be replaced like this:

#modify only the hi() below this line
hi(20) ---> this is the hi() i want to modify

Without the carat, it would replace the first match on BOTH lines, like this:

#modify only the hi(20) below this line
hi(20) ---> this is the hi() i want to modify

Or if you add a 'g' (s/^hi()/hi(20)/g) it will replace all occurrences on the matching lines:

#modify only the hi(20) below this line
hi(20) ---> this is the hi(20) i want to modify


I'm not sure how to explain why it would replace every instance in the file, as it seems to be doing in your case. What shell are you using? I'm testing in bash 3.2.25 with sed version 4.1.5.

EDIT: Also works as expected on OSX/bash 3.2.48, though I'm not sure of the sed version...

Edited 5 Years Ago by JeoSaurus: n/a

Well, let's assume the combination of 2 lines below is unique

#modify only the hi() below this line
hi()

Then "hi" will be the only hi() in return of the match. Then why do I still need the carat to specify it is at beginning of the line? By the way, all the hi() in my example text starts at beginning of line though.

I am just trying to understand if the ^ has anything to do with the multiple line match. Would sed '/match1/,/match2' matches "match1" on a line first and then check if "match2" is found on the line below? Sorry, it is hard without understanding its behavior for me.

sed '/#modify/,/hi()/

will find the

Okay, so the carat shouldn't have anything to do with the multi-line replacement that you're seeing. How many lines do you get from just this command: sed '/#modify/,/hi()/' ?

it looks like for some reasons

'/#modify/,/hi()/'

doesn't do what it supposed to do.

if I have the below text,

'/#modify/,/hi()/'

will find all the hi() in the text... im using bash 4.1.2(1) and sed 4.2.1 ... don't really think it matters though.. = /

#modify
hi()
123
hi()
1354
hi()
tthi()
dskf
jsdf
jsdkf
hi()


i googled around, found some source vaguely explain about sed '/pattern/,/pattern2/'.. can't find anything certainly tells me this will search 2 consecutive line for match though.

Sorry, I didn't give you the right syntax for running just the line matching (I left out the print command). It should look more like this: sed -n '/#modify/,/hi()/p' That should show you only the two lines we want.

sorry, but it doesn't look correct still....

[root@itoplinux m]# cat file
#!/bin/sh
Answ=""
b=0
c=1
d=2

Answ=""
Answ=""
dfjsl
Answ=""
dk
df23
Answ=""
z=0
=2
Answ=""
[root@itoplinux m]# sed -n '/Answ=""/,/z=0/p' file
Answ=""
b=0
c=1
d=2

Answ=""
Answ=""
dfjsl
Answ=""
dk
df23
Answ=""
z=0
Answ=""
[root@itoplinux m]#

Is there as well such a single sed command to remove several lines starting from my "label" line after all ?
May be something like : sed '/label/{d.....n;d...}' < filein > fileout ; mv fileout

Edited 5 Years Ago by Narue: Removed fake signature

This article has been dead for over six months. Start a new discussion instead.