3

I have a file as below . In which I want to remove lines under a particular sub heading alone. I tried using some sed and awk commands but I couldn't get it. Can any one help to crack this with some linux commands.

[first attempt]
a=10
b=20

[second attempt]
a=20
b=20

[third attempt ] 
a=30
b=50

I want to remove lines under '[second attempt]' sub heading alone. The output should be as below. I just want to remove the contents under the sub heading and optionally the removed lines can be replaced by one blank line

[first attempt]
a=10
b=20

[second attempt]

[third attempt ] 
a=30
b=50
4
  • 1
    Why are there two line breaks in the second version? Do you always want two line breaks, or does this depend on the number of empty lines in the original version?
    – Sparhawk
    Commented Oct 22, 2015 at 5:36
  • 1
    It would appear that you have accidentally created two accounts.  You should use the contact form and select “I need to merge user profiles” to have your accounts merged.  In order to merge them, you will need to provide links to the two accounts.  For your information, these are unix.stackexchange.com/users/139641/viju-m and unix.stackexchange.com/users/139642/viju.  You’ll then be able to edit, comment on and accept answers to this question. Commented Oct 22, 2015 at 6:29
  • The question has been exactly reversed. I was going to roll it back but then I saw this edit is apparently by the OP as his second identity. However, the answers below have all been made invalid by the edit as the question is completely different. EDIT: Actually I see Gilles voted to reject the edit. I agree with him; it is a destructive edit.
    – Wildcard
    Commented Oct 26, 2015 at 6:17
  • @Viju, I have reversed your edit. Please post a separate question instead of completely changing what you've asked. You also seem to have created two accounts, please see [here](unix.stackexchange.com/help/merging-accounts) for how to merge them.
    – terdon
    Commented Oct 26, 2015 at 12:16

4 Answers 4

1
awk -v blkid=0 -v rmblk=2 '{
      if ( $1 ~ /^\[/) {
            blkid+=1;blkn=NR;print };
      if ( blkid !=rmblk && NR!=blkn )
            print ;
      else if(blkid ==rmblk && NF == 0)
                  print ""}' file.txt

Each block will have id starting from 1 increment by one for each block: blkid.

The block id of the block you want remove : rmblk

Each block will start when first field starts with [.

The variable blkn stores the NR value of [first attempt] [second attempt] etc..

1
sed '$!N;/^\[second/,/^\n\[/P;D' <infile >outfile

That should probably do, though I'm not perfectly clear about what you want to do with the trailing blank line that immediately precedes the next section. This output includes it, because it seems the right thing to do, but if you want to drop only that one last blank line from any section that can be done relatively easily - so just ask.

Basically, for every input line which is ! not the $ last, sed also pulls in the Next line and appends it to pattern space following an inserted \newline character delimiter. Each time this happens the pattern space shifts:

 ^Line1\nLine2$
 ^Line2\nLine3$
 ^Line3\nLine4$

If the current pattern space matches the patterns ^\[second or ^\n\[ or any line which occurs between those two, sed will Print up to the first occurring \newline in pattern space - and so it only prints half of its buffer for each iteration.

Last, sed Deletes up to the first occurring \newline in pattern space and starts the script again from the top - which is how we get the shifting effect. This is known as a sliding window. It works very well, and is quite fast.


I guess there are multiple versions of this question or something? Whatever the case, going the opposite way is not so difficult to do, really.

You might do it like...

sed -ne '/^\[[^s]/,/^\[s/p' <in >out

Which would just print any content which doesn't follow a header beginning with an s character, and and all headers regardless. It doesn't do the neat little newline after, though:


[first attempt]
a=10
b=20

[second attempt]
[third attempt ]
a=30
b=50

If you want to get a little more explicit you can do that too:

sed '/^\[[second]/P;$!N;//,/\n$/!P;D' <in >out

...which does do the neat little newline...

[first attempt]
a=10
b=20

[second attempt]

[third attempt ]
a=30
b=50

All of these are sed ranges, and for each match expression that looks like:

/match1/,/match2/command

...sed will apply the command to both matched lines and all lines that come between.

1
  • You may want to change this as it was an answer to the inverted form of the question—an edit which has since been rolled back.
    – Wildcard
    Commented Oct 27, 2015 at 6:07
0

You can also do this with a short sed script. Put the following in a file:

/second/ {
   n
   : del
   /./ ! b
   N
   s/.*\n//
   b del
}

Call it script. Then use sed -f script myfile. If you are trying to edit the file in place, use sed -i -f script myfile, but I recommend running the first command before you try that and make sure it's exactly the output you want.

Explanation:

Once the string second is found, sed will look at the next line. If that line is not empty, it is discarded and the next line in the file is looked at until an empty line is found. That empty line and all other lines in the file are printed. (Unless there is another line containing the string second, in which case the process repeats.)

(I can explain more if anyone is interested.)

0

I'll try to grep to the two line numbers of "second attempt" and "third attempt" then delete whatever is in between. Edit accordingly to your needs. :)

#getting line number for [second attempt]
line_num_second=$(grep -n "second attempt" yourfile.txt | cut -d : -f 1)

#getting line number for [third attempt]
line_num_third=$(grep -n "third attempt" yourfile.txt | cut -d : -f 1)

start=$(expr $line_num_second +1)
end=$(expr $line_num_third -2)

#removes the content in between [second attempt] and [third attempt]
sed $start,"$end"d yourfile.txt

# sed -i $start,"$end"d yourfile.txt # -i - overwite/edit your files in-place instead of printing to standard output

You must log in to answer this question.

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