RajSanpui
RajSanpui

Reputation: 12094

sed - deleting n lines preceeding and following the matching pattern

Deleting "n" lines following the matching pattern is easy using something like:

IFM_MOUNT="/opt/insiteone/fuse-mount2/ifm"
sed -i "\|$IFM_MOUNT|,+6 d" smb.conf (deletes lines matching and next 6 lines)

But my problem is, i wish to delete 2 lines preceeding the matching pattern as well.

How to accomplish it? The file i will be invoking the command is a Samba configuration file which looks like this:

[DCCAArchive1]
        comment = DCCA Archive File System
        path = /opt/insiteone/fuse-mount1/ifm
        read only = No
        public = yes
        case sensitive = yes
        writable = yes
        create mask=0777
        guest ok = Yes

[DCCAArchive2]
        comment = DCCA Archive File System
        path = /opt/insiteone/fuse-mount2/ifm
        read only = No
        public = yes
        case sensitive = yes
        writable = yes
        create mask=0777
        guest ok = Yes

[DCCAArchive3]
        comment = DCCA Archive File System
        path = /opt/insiteone/fuse-mount3/ifm
        read only = No
        public = yes
        case sensitive = yes
        writable = yes
        create mask=0777
        guest ok = Yes

Upvotes: 1

Views: 159

Answers (2)

hek2mgl
hek2mgl

Reputation: 158100

You use the following sed command:

sed -r ':a;N;s~([^\n]*\n){2}[^\n]*'"$search"'\n~~;ba' file

The command works basically as a loop. :a marks a label at the loop start. N reads the next line of input and appends it to the pattern buffer. s~([^\n]+\n){2}PATTERN\n~~ will remove the pattern and two lines before it. Note that I'm using ~ as the delimiter since the input data contains the "standard" delimiter /. ba will branch back to the start of the loop. On the end of input the modified file gets printed $p.

Btw, it is simple to change the pattern to any amount of preceding lines by simply changing the 2 in the search pattern to whatever you want.

Upvotes: 0

Kent
Kent

Reputation: 195209

As I commented, if the format was fixed, (empty lines between data blocks), this line would do the job:

awk -v RS="" '!/PATTERN/' input

if it was not in this case, you can try this awk one-liner:

awk '{a[NR]=$0}/PATTERN/{for(i=NR-2;i<=NR+6;i++)d[i]=1}
     END{for(i=1;i<=NR;i++)if(!d[i])print a[i]}' input

a test

  • with ifm as simplified PATTERN
  • no empty lines between "data blocks"
  • follows your rule: remove lines hit-2 -> hit+6

    kent$  cat f
    fooooooooo
    [DCCAArchive1]
            comment = DCCA Archive File System
            path = /opt/insiteone/fuse-mount1/ifm
            read only = No
            public = yes
            case sensitive = yes
            writable = yes
            create mask=0777
            guest ok = Yes
    barrrrrrrrrrrr
    [DCCAArchive2]
            comment = DCCA Archive File System
            path = /opt/insiteone/fuse-mount2/ifm
            read only = No
            public = yes
            case sensitive = yes
            writable = yes
            create mask=0777
            guest ok = Yes
    
    kent$  awk  '{a[NR]=$0}/ifm/{for(i=NR-2;i<=NR+6;i++)d[i]=1}END{for(i=1;i<=NR;i++)if(!d[i])print a[i]} ' f
    fooooooooo
    barrrrrrrrrrrr
    

Edit

use pattern from shell variable:

kent$  PAT="/fuse-mount2/ifm"

kent$  awk -v p="$PAT" '{a[NR]=$0}{if(match($0,p)>0){for(i=NR-2;i<=NR+6;i++)d[i]=1}}END{for(i=1;i<=NR;i++)if(!d[i])print a[i]} ' f                                          
fooooooooo
[DCCAArchive1]
        comment = DCCA Archive File System
        path = /opt/insiteone/fuse-mount1/ifm
        read only = No
        public = yes
        case sensitive = yes
        writable = yes
        create mask=0777
        guest ok = Yes
barrrrrrrrrrrr

Upvotes: 3

Related Questions