How to delete lines before and after matching pattern

319 Views Asked by At

i have a file like below. I want to search pattern ABC_DATA as a variable and after match, i want to delete from first previous "multipath" line to the line including "}" character. "}" could be after or in the same line with ABC_DATA.

SAMPLE OUTPUT

multipaths {
multipath {
wwid 360000970000267600432533030353944
alias ABC_DATA_11
}
multipath {
wwid 360000970000267600432533030353945
alias DEF_DATA_11
}
multipath {
wwid 360000970000267600432533030353946
alias ABC_DATA_12 }

multipath {
wwid 360000970000267600432533030353943
alias DEF_DATA_10
}
}

EXPECTED OUTPUT

multipaths {
multipath {
wwid 360000970000267600432533030353945
alias DEF_DATA_11
}
multipath {
wwid 360000970000267600432533030353943
alias DEF_DATA_10
}
}
4

There are 4 best solutions below

6
On BEST ANSWER
$ awk -v RS='multipath\\s*{[^}]*ABC_DATA[^}]*}\\s*(\n|$)' -v ORS= '1' file
multipaths {
multipath {
wwid 360000970000267600432533030353945
alias DEF_DATA_11
}
multipath {
wwid 360000970000267600432533030353943
alias DEF_DATA_10
}
}
0
On

ed(1) works too, if you have the global search strings on different lines than the start+end lines of the area which you want to delete:

echo $'g/ABC_DATA/?multipath?,/[\s\S]*}/s/.*//g\n ,n\n w\n q' | ed -s file
#or
echo $'g/ABC_DATA/?multipath?,/[\s\S]*}/d\n ,n\n w\n q' | ed -s file
  • echo command supplies the ed commands, \n are just newlines
  • same could be achieve with heredocs or ed script files, but that doesnt work for oneliners

whats actually happening there:

  • search for ABC_DATA
  • from there get the starting line by searching for multipath upwards
  • get the ending line by searching downwards for any char ([\s\S]*) and ending with }
  • and either "sed" it via s or delete via d
  • ,n is just for printing all output to shell and can be ommitted
  • w saves and q exits - use Q instead of both if you are still experimenting and dont want to save changes immediately back to the file

however this will fail for this example due to the line containing alias ABC_DATA_12 } as both ABC_DATA and } are on the same line - i still can see merit for using ed(1) and thus wanted to share this approach.

1
On

Given your example, you can use this perl:

$ perl -0777 -lpe 's/\bmultipath\h+\{[^{}]*ABC_DATA[^{}]*}\s*//g' file
multipaths {
multipath {
wwid 360000970000267600432533030353945
alias DEF_DATA_11
}
multipath {
wwid 360000970000267600432533030353943
alias DEF_DATA_10
}
}
0
On

Using sed, not really readable but definitely possible:

sed '
   /^multipath {/ {
     :l
     /alias ABC_DATA/ {
       :f
       /}/ d
       N
       b f
     }
     /}/ b
     N
     b l
  }' input

or as a single line:

sed '/^multipath {/{:l; /alias ABC_DATA/{:f /}/d;N;bf};/}/b;N;bl};' input