0

I have a file with the following content:

dn : Does not matter
 uid=321 456 678
foo=/234
bar=/456
git=/543

 uid=321 456 678
 uid=678 987 098
foo=/234
bar=/456
git=/543

dn : Does it matter
 uid=321 456 678
foo=/543
bar=/423
git=/501

I want to remove any occurrences of uid= that occurs consecutively and also the 3 lines following it so that the expected output is:

 dn : Does not matter
 uid=321 456 678
foo=/234
bar=/456
git=/543

dn : Does it matter
 uid=321 456 678
foo=/543
bar=/423
git=/501

I have tried that on two servers. Unfortunately, I do not have access to the one server where I had tried the bulk of my attempts. So from the second server I have tried variations of the following but desired results are eluding me.

sed '/^ uid=/N;{/\n uid= & & \n ^change type & & \n ^replace/d;}' pattern2.txt
awk '{/pat/?f++:f=0} f==2 {f--;}; 1' < pattern2.txt
sed '/^ uid=/N;{/\n uid=/D;}' pattern1.txt
awk '{/ uid=/?f++:f=0} f==2' pattern1.txt
8
  • i had posted the pattern in new lines. However, this seems to be garbled up on posting
    – crusader
    May 6, 2018 at 15:09
  • I've formatted it to preserve newlines.. in future, check unix.stackexchange.com/editing-help for help(in short, select the lines and use ctrl+k or press the {} editing icon)
    – Sundeep
    May 6, 2018 at 15:12
  • also, does your input always have empty line separating the blocks containing uid=? if so, using awk's paragraph mode is the easiest way to solve this
    – Sundeep
    May 6, 2018 at 15:21
  • yes, it invariably has the empty line separating the blocks 2 consecutive " uid="
    – crusader
    May 6, 2018 at 15:23
  • can you check if awk -v RS= -v ORS='\n\n' '!/uid=.*uid=/' solves your problem? this works for given sample but might not work for your real use case
    – Sundeep
    May 6, 2018 at 15:23

2 Answers 2

0

Using sed:

$ sed -f script.sed file
dn : Does not matter
 uid=321 456 678
foo=/234
bar=/456
git=/543

dn : Does it matter
 uid=321 456 678
foo=/543
bar=/423
git=/501

... where script.sed is

H              # Append a newline and the current line to the hold space
/^$/bout       # Empty line: branch to ':out'
$bout          # Last line: branch to ':out'
d              # Delete line, start again from the top
:out
x              # Swap in the data from the hold space
/uid.*uid/d    # Delete the data if it contains two "uid"
s/\n//         # Remove the first embedded newline
               # (implicit print)

This collects the read lines in the "hold space" (a general purpose buffer in sed) and when it hits an empty line or the end of input, the hold space contains one of the "blocks" in the original file. If such a block contains two instances of the string uid, it is discarded, otherwise it is outputted.

0

With awk - I feel this could be simplified, but not able to so far

awk '/uid=/ && p~/uid=/{c=4; next}
     !(c && c--) && NR>1{print p} {p=$0}
     END{if(c==0)print p}' ip.txt
  • by default, uninitialized variables in awk will be empty string or 0 depending on context
  • /uid=/ && p~/uid=/ if current and previous line contains uid=
    • c=4; next initialize c with number of lines to skip(plus 1 because of logic I ended up with). Also, skip rest of the code
  • !(c && c--) && NR>1{print p} print previous line if current line number is greater than 1 and if c==0. If c is greater than 0, it will continue decrementing until c==0
  • {p=$0} save previous line for further use
  • END{if(c==0)print p} print the last line if c==0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .