LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-25-2009, 05:37 AM   #1
wakatana
Member
 
Registered: Jul 2009
Location: Slovakia
Posts: 141

Rep: Reputation: 16
SED interval specification


Hi all

input
Code:
BEGIN
some other text
containing words
such as BEGIN
and END
END
some other text
containing words
such as BEGIN
and END
BEGIN
some other text
containing words
such as BEGIN
and END
END

desired output
Code:
 
BEGIN
some other text
containing words
such as START
and EXIT
END
some other text
containing words
such as BEGIN
and END
BEGIN
some other text
containing words
such as START
and EXIT
END
In conclusion replace all BEGIN with START and END with EXIT but only within BEGIN END boundaries.

I tried that
Code:
cat begendf | sed '/^BEGIN/,/^END/ s/BEGIN/START/; s/END/EXIT/'
START
some other text
containing words
such as START
and EXIT
EXIT
some other text
containing words
such as BEGIN
and EXIT
START
some other text
containing words
such as START
and EXIT
EXIT
But as you can see also replaced boundaries (BEGIN, END to START, EXIT) and leaves unchanged only BEGIN and not END outside the boundaries.
Also tried some weird tricks using new spaces but neither working. Thanks a lot.
 
Old 10-25-2009, 06:22 AM   #2
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,

This: s/BEGIN/START/; s/END/EXIT/, will find all (!!) BEGIN and END lines, including the ones in the range.

The scond part (all after the ; ) is not a part of the range specified in the first part, try this:

sed -e '/^BEGIN/,/^END/s/ BEGIN/ START/' -e '/^BEGIN/,/^END/s/ END/ EXIT/' infile

2 sed actions (made possible by the -e options), first one for the BEGIN/END part, second for the END/EXIT part. Both are bound to a specific section.

You could also rewrite it to:

sed '/^BEGIN/,/^END/{s/ BEGIN/ START/;s/ END/ EXIT/}' infile

All between the curly brackets ({...}) is bound by the section part.

Hope this helps.
 
Old 10-25-2009, 06:43 AM   #3
wakatana
Member
 
Registered: Jul 2009
Location: Slovakia
Posts: 141

Original Poster
Rep: Reputation: 16
druuna thanks a lot this really helps,
I saw lot of sed examples including -e option also read man but it was still unclear what is it for, if it works without it
Now I know I should use it if I have multiple actions.
I am wondering to one thing, in example that you've posted you replace

s/ END/ EXIT/
and
s/ BEGIN/ START/

that works because of whitespace (space in this case) before matching string.
But is possible to exclude somehow the boundaries, from replacement ?
So I could rewrite it to


s/END/EXIT/
and
s/BEGIN/START/


and still be working.

Thanks

Last edited by wakatana; 10-25-2009 at 06:44 AM.
 
Old 10-25-2009, 06:45 AM   #4
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Rep: Reputation: 107Reputation: 107
Thumbs up

I have done this through a dirty way . I am calling this dirty as this could have been done through sed/awk one liners like druuna has done, BUT my knowledge is limited to sed/awk.

Anyways, here is my script. I am assuming your file is named as file.
And your desired output would be in file2.

Code:
> /tmp/file1
while read i
do
echo $i | grep ^BEGIN
if [ $? -eq 1 ]
then
  echo $i | grep BEGIN
     if [ $? -eq 0 ]
       then
       echo $i | sed 's/BEGIN/START/' >> file1
     else
       echo $i >> file1
     fi
else
echo $i >> file1
fi
done < file


> /tmp/file2
while read i
do
echo $i | grep ^END
if [ $? -eq 1 ]
then
  echo $i | grep END
     if [ $? -eq 0 ]
       then
       echo $i | sed 's/END/EXIT/' >> file2
     else
       echo $i >> file2
     fi
else
echo $i >> file2
fi
done < file1
Hope it helps.
 
Old 10-25-2009, 06:47 AM   #5
vonbiber
Member
 
Registered: Apr 2009
Distribution: slackware 14.1 64-bit, slackware 14.2 64-bit, SystemRescueCD
Posts: 533

Rep: Reputation: 129Reputation: 129
Quote:
Originally Posted by wakatana View Post
input
Code:
BEGIN
some other text
containing words
such as BEGIN
and END
END
some other text
containing words
such as BEGIN
and END
BEGIN
some other text
containing words
such as BEGIN
and END
END
Another possible solution would be to
1. temporarily replace 'BEGIN' and 'END' that start a line
by a unique string
2. replace all other occurences of 'BEGIN' and 'END'
3. restore the original values of the replacements in 1.
e.g.
Code:
<your input> | sed 's?^BEGIN$?__@@@__?' | sed 's?^END$?__///__?' | \
    sed 's?BEGIN?START?g' | sed 's?END?EXIT?g' | \
    sed 's?__@@@__?BEGIN?' | sed 's?__///__?END?'
 
Old 10-25-2009, 06:52 AM   #6
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by vonbiber View Post
Another possible solution would be to
1. temporarily replace 'BEGIN' and 'END' that start a line
by a unique string
2. replace all other occurences of 'BEGIN' and 'END'
3. restore the original values of the replacements in 1.
e.g.
Code:
<your input> | sed 's?^BEGIN$?__@@@__?' | sed 's?^END$?__///__?' | \
    sed 's?BEGIN?START?g' | sed 's?END?EXIT?g' | \
    sed 's?__@@@__?BEGIN?' | sed 's?__///__?END?'
This is a nice solution, nice thinking. It did not clicked me. I coded all the way
 
Old 10-25-2009, 06:59 AM   #7
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Quote:
Originally Posted by wakatana View Post
I am wondering to one thing, in example that you've posted you replace

s/ END/ EXIT/
and
s/ BEGIN/ START/

that works because of whitespace (space in this case) before matching string.
But is possible to exclude somehow the boundaries, from replacement ?
So I could rewrite it to


s/END/EXIT/
and
s/BEGIN/START/


and still be working.
No, not without doing extra work (vonbiber idea comes to mind).

I'm not sure why you need to get rid of the space, it seems to be the simplest solution.
 
Old 10-25-2009, 07:38 AM   #8
wakatana
Member
 
Registered: Jul 2009
Location: Slovakia
Posts: 141

Original Poster
Rep: Reputation: 16
hi vikas027
Thank you for you reply, I am staring at your script (cause I am beginner in bash scripting) and cannot figure out what is $? in [ $? -eq 1 ] and [ $? -eq 0 ]
I know that -eq 1(0) is condition testing for equaling to 1(0) but what is $? ?

vonbiber: Interesting solution, thanks I had to a little change code to to what I want but preserves your idea

Code:
cat begendf | sed 's?^BEGIN$?__@@@__?' | sed 's?^END$?__]]]__?' |\
sed '/__@@@__/,/__]]]__/{s/BEGIN/START/;s/END/EXIT/}' |\
sed 's/__@@@__/BEGIN/g; s/__]]]__/END/'
 
Old 10-25-2009, 07:42 AM   #9
wakatana
Member
 
Registered: Jul 2009
Location: Slovakia
Posts: 141

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by druuna View Post
I'm not sure why you need to get rid of the space, it seems to be the simplest solution.
No I wont, just for interesting
And last question just for interesting

can i use another "delimiter" (or separator or what is correct name) in interval ?

/__@@@__/,/__]]]__/
tried
?__@@@__?,?__]]]__?
but did not work

Last edited by wakatana; 10-25-2009 at 07:45 AM.
 
Old 10-25-2009, 07:49 AM   #10
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by wakatana View Post
hi vikas027
Thank you for you reply, I am staring at your script (cause I am beginner in bash scripting) and cannot figure out what is $? in [ $? -eq 1 ] and [ $? -eq 0 ]
I know that -eq 1(0) is condition testing for equaling to 1(0) but what is $? ?
Hi,

Well $? stores the result of the last command you have run. If a command is successful it returns 0 else 1.

For .eg.

Code:
-sh-3.00$ rm abc
rm: cannot remove `abc': No such file or directory
-sh-3.00$ echo $?
1
Now,
Code:
-sh-3.00$ touch abc
-sh-3.00$ rm abc
-sh-3.00$ echo $?
0
Hope, this helps.
 
Old 10-25-2009, 08:57 AM   #11
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Using this sample input file, modified slightly for the first BEGIN,END block
Code:
$ more file
BEGIN
some other text
containing words
such as BEGIN
END and END END
END
some other text
containing words END
such as BEGIN
and END
BEGIN
some other text
containing words
such as BEGIN
and END
END
awk code:
Code:
awk '
/^END$/{f=0}
/^BEGIN$/{f=1;print;next}
f{ 
 gsub("BEGIN","START")
 gsub("END","EXIT")
 print $0
}f==0' file
output
Code:
$ ./shell.sh
BEGIN
some other text
containing words
such as START
EXIT and EXIT EXIT
END
some other text
containing words END
such as BEGIN
and END
BEGIN
some other text
containing words
such as START
and EXIT
END
NB: ALL sed solutions provided fails on this sample input.

Last edited by ghostdog74; 10-25-2009 at 09:04 AM.
 
Old 10-25-2009, 09:01 AM   #12
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by vikas027 View Post
This is a nice solution, nice thinking.

no its not. Its ugly, unreadable and full of unnecessary chaining. Use sed for simple substitution.
 
Old 10-25-2009, 09:23 AM   #13
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
@ghostdog74: You are not using the original posted input. Other solutions are indeed needed if the input is different, but that wasn't the OP's original question.......

Quote:
no its not. Its ugly, unreadable and full of unnecessary chaining. Use sed for simple substitution.
And what's wrong with the small and elegant sed solution (a one-liner, not a script) I posted in reply #2???

I'm talking about this one:

sed '/^BEGIN/,/^END/{s/ BEGIN/ START/;s/ END/ EXIT/}' infile
 
Old 10-25-2009, 09:23 AM   #14
vikas027
Senior Member
 
Registered: May 2007
Location: Sydney
Distribution: RHEL, CentOS, Ubuntu, Debian, OS X
Posts: 1,305

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by ghostdog74 View Post
no its not. Its ugly, unreadable and full of unnecessary chaining. Use sed for simple substitution.
Hi,

I just meant about these steps, not the code. I could not understand the code even.
Yes, this can be done by sed in just three lines as per my knowledge.
Code:
1. temporarily replace 'BEGIN' and 'END' that start a line
   by a unique string
2. replace all other occurences of 'BEGIN' and 'END'
3. restore the original values of the replacements in 1.
 
Old 10-25-2009, 09:43 AM   #15
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by druuna View Post
@ghostdog74: You are not using the original posted input. Other solutions are indeed needed if the input is different, but that wasn't the OP's original question.......
please look at the input again. it says "some other text containing words
such as BEGIN and END". there may be other ENDs and BEGINs at different places inside BEGIN,END blocks, besides the ones OP posted


Quote:
And what's wrong with the small and elegant sed solution (a one-liner, not a script) I posted in reply #2???

I'm talking about this one:

sed '/^BEGIN/,/^END/{s/ BEGIN/ START/;s/ END/ EXIT/}' infile
I am not talking about your code. Please see my reply again to Vikas. The sed solution he quoted is not provided by you.

Also, I did not say its wrong to use small elegant sed solution. I did say use sed for simple substitution. Anything beyond , like that of post
#5, code will get ugly and hard to decipher especially if anything went wrong.
 
  


Reply

Tags
replace, sed



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
commit interval 5 seconds mscorsese Linux - Newbie 1 10-01-2009 06:52 PM
copying between interval scofiled83 Programming 5 04-04-2009 08:34 PM
Using grep with interval expression... Chikne Slackware 2 04-13-2007 11:04 AM
Log netstat at interval DaHoe Linux - Newbie 4 11-06-2006 02:11 AM
hid interval patch some Linux - Newbie 5 12-04-2003 06:28 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:56 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration