Operating System - HP-UX
1752290 Members
4770 Online
108786 Solutions
New Discussion юеВ

sed - deletion of multiple lines in a file

 
SOLVED
Go to solution
Eric Lipede
Frequent Advisor

sed - deletion of multiple lines in a file

Hi

Scenario
========
I have a file with the word root appearing randomly in it. Ie on line 7 , 13 , 27 etc.
Id like to delete the line containing "root" and 2 lines above it and 2 lines below it (in a script). Any ideas?
thks
Quod sum eris
22 REPLIES 22
James R. Ferguson
Acclaimed Contributor
Solution

Re: sed - deletion of multiple lines in a file

Hi Eric:

# cat snip2
#!/usr/bin/perl
use strict;
use warnings;
my $skip = 0;
my @lines;
while (<>) {
chomp;
if (/root/) {
$skip=2;
pop @lines for (1..$skip);
next;
}
if ($skip-- <= 0) {
push(@lines,$_);
}
}
print "$_\n" for (@lines);
1;

...run as:

# ./snip2 file

Regards!

...JRF...
Hein van den Heuvel
Honored Contributor

Re: sed - deletion of multiple lines in a file

Here is a silly one-liner.

perl -ne 'print $l3 if --$root<0; $l3=$l2; $l2=$l1;$l1=$_; $root=5 if /root/}{print $l3 if --$root<0; print $l2 if --$root<0; print $l1 if --$root<0' tmp.txt

In slow motion...

while (<>) {
print $l3 if --$root<0; # only if no root in near future
$l3=$l2; # delay line...
$l2=$l1;
$l1=$_;
$root=5 if /root/
}
# deal with last lines;
print $l3 if --$root<0;
print $l2 if --$root<0;
print $l1 if --$root<0;

So many ways to do it.

This probaly codes more tightly using a simple 3 line array indexed by ( $. % 3 )

Cheers,
Hein.



Eric Lipede
Frequent Advisor

Re: sed - deletion of multiple lines in a file

Hi Guys
points a-coming ..great perl solutions ....only we arent using perl could i bother you for the awk / sed equivalents - many thks


****** grep for the stars
Quod sum eris
Hein van den Heuvel
Honored Contributor

Re: sed - deletion of multiple lines in a file

perl -ne 'print $l[($.-3)%3] if --$root<0; $l[$.%3]=$_; $root=5 if /root/} {for $i ($.-2 .. $.) { print $l[$i%3] if --$root<0}' tmp.txt

Same method of course also works in awk, but you have to not try to print for the first 3 lines.

$ awk '(--r<0 && NR>3) {print l[(NR-3)%3]} /root/ {r=5} {l[NR%3]=$0} END {for (i=NR-2; i<=NR; i++) {if (--r<0) {print l[i%3]}}}'


perl array solution pretty printed....

while (<>) {
print $l[($.-3)%3] if --$root<0;
$l[$.%3]=$_;
$root=5 if /root/;
}
for $i ($.-2 .. $.) {
print $l[$i%3] if --$root<0
}

Hein
James R. Ferguson
Acclaimed Contributor

Re: sed - deletion of multiple lines in a file

Hi (again):

TMTOWTDI.

...JRF...
Eric Lipede
Frequent Advisor

Re: sed - deletion of multiple lines in a file

Hi Hein
Im trying to modify the awk script to:
delete the previous 9 lines and 9 lines after the found text "root is not locked"
(including the found text)

file is....
*************************************************
Cron: The previous message is the standard output
and standard error of one of your crontab commands:

/hpuxsw/utilities/health/unlr.sh


From SYSTEM-ALERT@rx86 Thu Jun 26 15:00:01 BST 2008
Received: (from root@localhost)
by x.sw.corp (8.11.1 (PHNE_35485)/8.11.1) id m5QE01218793
for root; Thu, 26 Jun 2008 15:00:01 +0100 (BST)
Date: Thu, 26 Jun 2008 15:00:01 +0100 (BST)
From: SYSTEM-ALERT@rx86
Message-Id: <200806261400.m5QE01218793@lonunix2.sw.corp>
Subject: cron

root is not locked


*************************************************
Cron: The previous message is the standard output
and standard error of one of your crontab commands:

/hpuxsw/utilities/health/unlr.sh





...not having much joy ! :-(
Quod sum eris
James R. Ferguson
Acclaimed Contributor

Re: sed - deletion of multiple lines in a file

Hi Eric:

Well, you could modify the Perl script I suggested in response to your last query.

Change:

$skip=2;

to

$skip=9;

...and anchor (with a caret) the match for the word "root" like:

if (/^root/) {

As I said, TMTOWTDI.

Regards!

...JRF...


James R. Ferguson
Acclaimed Contributor

Re: sed - deletion of multiple lines in a file

Hi (again) Eric:

I hope that your lack of credit for my efforts isn't a case of "Condemnant quod non intellegunt" but rather a simple, unintentional oversight.

...JRF...
Hein van den Heuvel
Honored Contributor

Re: sed - deletion of multiple lines in a file

Eric>> only we arent using perl could i bother you for the awk / sed equivalents

I had need seen this when i volunteerd the awk solution. I probably would not have done the awk alternate had I read that :^).

Please consider ANY solution when kindly offered, and reward the effort.
Admittedly you did mention 'sed' in the subject.

Let's face is you ( your peers ) could not solve it in the language of your choice, so clearly (for me) that language holds no (maintenance) advantage.
Any non-sed solution is surely just as hard (easy) to understand / maintain whether it be perl or awk or shell or any other 'likely to be available' language.

Anyway...

Eric>> Im trying to modify the awk script to:

Well, my first awk and perl suggestions would be too tedious to grow the 'delay line / bucket brigade'

The second awk suggestion, with the array, is more flexible, but was spinkled with delete window dependend contants.

James's solution is much cleaner in that he need to set the number of lines to skip just once: $skip=2;
So just one edit needed to change to 9 lines.

His solution build a potentiall very large array of lines to keep, so he can print it all at the end. Note, his solution might miss a re-occurance of 'root' in the deleted lines which may or might not be desirable. With the newer specification it is clear that is a moot point thought.

My solution has a one-on-one print but 'lagging' by N lines. So it has the drwaback of needing to fix what is still in the queue on reading the last record.

Anyway here is an (awk) version of the script with the 'Window' exposed as variable:

------------- filter.awk -----------
BEGIN { Window = 9 + 1}
(--Count<0 && NR > Window ) {print line[(NR - Window)%Window]}
/root is not locked/ {Count=2*Window - 1}
{line[NR%Window]=$0}
END {
for (i=NR-Window; i i++;
if (--Count<0) {
print line[i%Window];
}
}
}
------------------

awk -f filter.awk

cheers,
Hein.