LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
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
 
LinkBack Search this Thread
Old 03-21-2008, 07:02 AM   #1
0.o
Member
 
Registered: May 2004
Location: Raleigh, NC
Distribution: Debian, Solaris, HP-UX, AIX
Posts: 196

Rep: Reputation: 31
Remove 38 lines after finding match


Hello,


I need to edit a MRTG config file that has about 5000 targets in it. Needless to say i don't want to go through and remove one at a time. I need to look for a match on the word 'Target' and then on the word Bundle. Once that combination is found, remove exactly 38 lines from there to the bottom. The only way I can think of doing it is with perl and a counter. I am sure there is a way with awk, i just don't know it well enough to complete this. Do any of you know of a way to do this?

--Thanks
 
Old 03-21-2008, 09:07 AM   #2
jschiwal
Moderator
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,263

Rep: Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562
Maybe not the best solution. The range '1,/Target.*bundle/' selects from the beginning of the file to the "Target" line. The range /Target.*bundle/,+38 selects the "Target" line and the next 38 lines.

Code:
sed -n '1,/Target.*Bundle/p;/Target.*Bundle/,+38{ /Target.*Bundle/!p }' testc
I hope your version of SED can use ranges like this.

Last edited by jschiwal; 03-22-2008 at 03:26 AM.
 
Old 03-21-2008, 07:40 PM   #3
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 64
Either I don’t understand or I don’t see what’s wrong with this:
Code:
sed '/Target.*Bundle/,+38{/Target.*Bundle/!d }'

Last edited by osor; 03-24-2008 at 12:25 PM. Reason: change lowercase ‘b’ to uppercase
 
Old 03-21-2008, 08:13 PM   #4
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 10,467

Rep: Reputation: 627Reputation: 627Reputation: 627Reputation: 627Reputation: 627Reputation: 627
I don't know MRTG, but is it always the case that "Target" and "bundle" will be on the same line ???.
 
Old 03-22-2008, 03:42 AM   #5
jschiwal
Moderator
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,263

Rep: Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562
Quote:
Originally Posted by osor View Post
Either I don’t understand or I don’t see what’s wrong with this:
Code:
sed '/Target.*bundle/,+38{/Target.*bundle/!d }'
This will delete the line with "Target.*bundle" in it. It will print the lines after the 38th line however.
Code:
sed -n '1,/Target.*Bundle/p;/Target.*Bundle/,+38{ /Target.*Bundle/!p }' testc
Note that the "testc" file was just the name of the file I used to test the sed command. That part would be changes to something like mtrg.conf >mtrg.conf.new

The "-n" part causes sed to not print out lines unless you use the "p" print command. This is often used if you want to extract information from the original instead of editing parts of a file.

Note the semicolon in the middle of the command. This is one way of using more than one sed command on a oneliner. Another is the form "sed -e 'command1' -e 'command2'.
The first command prints all of the lines from 1 to the line with the words Target and Bundle in it.
The second command first matches all lines from the "Target.*Bundle" line and the next 38 lines. The sub-range matches the same lines that don't match the "Target.*Bundle" line. This prevents the "Target.*Bundle" line from being printed twice.

I will often use sed to print out a section of the output of commands like "lspci -v" which separate segments with blank lines:
sed -n '/NVidia/,/^$/p'

This is a common type of output that is used to make it easy to process with sed or awk. In awk you can have one field on each line with a blank line separating records.

Last edited by jschiwal; 03-22-2008 at 03:49 AM.
 
Old 03-22-2008, 04:21 AM   #6
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 10,467

Rep: Reputation: 627Reputation: 627Reputation: 627Reputation: 627Reputation: 627Reputation: 627
Quote:
Originally Posted by jschiwal View Post
This will delete the line with "Target.*bundle" in it. It will print the lines after the 38th line however.
Not on my system.
It deletes (precisely) the 38 lines following the address line.

As was requested.
 
Old 03-22-2008, 04:51 AM   #7
jschiwal
Moderator
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,263

Rep: Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562
You are right. I missed the negation. However, I think the user wants to keep the next 38 lines but delete the 39th to the bottom of the the file.

Maybe the phrase "to the bottom" threw me off from what the OP wants.

The phrase "from there" does tend to imply "the next 38 lines"; but along with "to the bottom" I don't think the OP wants from the matching line to the end of the file, because the 38 lines would be meaningless.

A fragment of a real sample along with the desired result would help explain what is wanted and make testing the answer easier.
 
Old 03-22-2008, 09:34 PM   #8
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 64
Quote:
Originally Posted by jschiwal View Post
Code:
sed -n '1,/Target.*Bundle/p;/Target.*Bundle/,+38{ /Target.*Bundle/!p }' testc
This will print all lines from the first line down to the first line containing the RE in question. Then, it will print the 38 lines following each other instance of the same RE (not including the line containing the RE itself). I don’t understand why you chose to keep the lines following the first occurrence of the RE, regardless of how you read the OP. In my reading of the OP, it specifically asked to “remove exactly 38 lines from there” (but in yours, you remove everything but the lines).

Anyhow, both our solutions make use of GNU sed features, and 0.o lists FreeBSD and Solaris in the profile. So if you are forced to use POSIX versions of the standard tools, you can use a counter in awk similar to how you would in Perl. For example,
Code:
awk 'BEGIN{a=38};a++>37;/Target.*Bundle/{a=0}'
is the equivalent of my GNU sed solution (except it has different behavior when two instances of the RE appear within 38 lines of each other).

Last edited by osor; 03-24-2008 at 12:25 PM. Reason: change lowercase ‘b’ to uppercase
 
Old 03-23-2008, 10:48 AM   #9
jschiwal
Moderator
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,263

Rep: Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562
Without the sample input it is hard to tell what is wanted. I took "to the bottom" to mean "to the end of the file".
 
Old 03-24-2008, 08:16 AM   #10
0.o
Member
 
Registered: May 2004
Location: Raleigh, NC
Distribution: Debian, Solaris, HP-UX, AIX
Posts: 196

Original Poster
Rep: Reputation: 31
Sorry for the late response. The input will look like this:

Code:
Target[172.22.9.149_Bundle50]: \Bundle50:community@172.22.9.149:::3:2:2
SnmpOptions[172.22.9.149_Bundle50]:  
nohc[172.22.9.149_Bundle50]: yes
SetEnv[172.22.9.149_Bundle50]: MRTG_INT_IP="<SOME PUB IP>" MRTG_INT_DESCR="Bundle50"
MaxBytes[172.22.9.149_Bundle50]: 75000000
Title[172.22.9.149_Bundle50]: Bundle50  
PageTop[172.22.9.149_Bundle50]: <h1>Traffic Analysis for Bundle50</h1>
                <div id="sysdetails"> 
                        <table>
                                <tr>
                                        <td>System:</td>
                                        <td>CHSPCMTK01HR.coxfiber.net in CHSPCMTK01</td>
                                </tr>         
                                <tr>  
                                        <td>Maintainer:</td>
                                        <td>CHSPCMTK01</td>
                                </tr>         
                                <tr>  
                                        <td>Description:</td>
                                        <td>Bundle50  </td>
                                </tr>         
                                <tr>  
                                        <td>ifType:</td>
                                        <td>CATV MAC Layer (127)</td>
                                </tr>         
                                <tr>  
                                        <td>ifName:</td>
                                        <td>Bu50</td>
                                </tr>         
                                <tr>  
                                        <td>Max Speed:</td>
                                        <td>600.0 Mbits/s</td>
                                </tr>         
                                <tr>  
                                        <td>Ip:</td>
                                        <td>68.228.136.1 ()</td>
                                </tr>         
                        </table>      
                </div>
That entry is exactly 38 lines long, and there are quite a few of them. What i want to do is find 'Target' then find 'Bundle', if they both exists, remove 38 lines following them.

Last edited by 0.o; 03-24-2008 at 08:17 AM.
 
Old 03-24-2008, 12:25 PM   #11
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 64
Quote:
Originally Posted by 0.o View Post
What i want to do is find 'Target' then find 'Bundle', if they both exists, remove 38 lines following them.
If they both exist on the same line? So for the above input, the correct output would be the following.
Code:
Target[172.22.9.149_Bundle50]: \Bundle50:community@172.22.9.149:::3:2:2
Is that correct?

If so, did you try my two solutions (originally, I had a lowercase ‘b’ but I changed them now to match an uppercase ‘B’)?
 
Old 03-24-2008, 01:20 PM   #12
0.o
Member
 
Registered: May 2004
Location: Raleigh, NC
Distribution: Debian, Solaris, HP-UX, AIX
Posts: 196

Original Poster
Rep: Reputation: 31
Yep. It got it to work. I had to change a few things, but it works. I really appreciate your help!
 
Old 03-28-2008, 02:15 AM   #13
jschiwal
Moderator
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,263

Rep: Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562Reputation: 562
Would the line count be accurate in the future?

You might want to use something like
sed '/^Target.*Bundle/,/<\/div>/{ /Target.*Bundle/!d }'
instead in case after an update or for different targets there are other fields added or changed. This solution depends on the <div id> ..</div> section appearing last.

If there is a blank line following target entries, that would make things easier:
sed '/^Target.*Bundle/,/^$/{ /Target.*Bundle/!d }'

sed '/PATTERN/,/^$/ ... is a common idiomatic pattern for selecting sections of an output, such as the output of lspci.

In awk, you can change FS to "\n" and RS to "" ('BEGIN {FS="\n"; RS=""} ...) to handle this type of input where each line is a filed and a blank line separates records.

If every record starts with the Target.*Bundle line and each record is separated by blank lines, then you simply need to print the first line of each record:
awk 'BEGIN {FS="\n"; RS=""} { print $1 }' file >newfile

When using sed, awk or perl to extract the information you want, the structure of the file is the most important information. It is what regex patterns depend on.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Finding duplicate lines in a file MikeyCarter Linux - Software 3 10-05-2008 05:28 PM
REGEXP Match * through multiple lines ? ALInux Linux - Software 12 08-14-2007 07:39 AM
Using diff and erasing the lines that match ElectroLinux Linux - Newbie 4 09-20-2006 03:34 AM
VIM finding and commenting lines shamgar03 Linux - Software 3 06-06-2006 04:49 PM
Finding lines in file1,but not in file 2 subu_s Programming 2 12-14-2004 09:56 AM


All times are GMT -5. The time now is 05:12 AM.

Main Menu
 
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
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration