I have a text file called file_a.txt. My first command is

grep -A 12 ".production =" file_a.txt

The output is a few block. Each block of string contains 13 rows

I specifically want to delete all the block of strings I got with the grep command from the original file file_a.txt. I do not want to send the grep output to a new file. Also I do not want to to use grep -v because it will not work in my case.

I have tried something like things like this, but nothing is working:

cut < grep -A 12 ".production =" file_a.txt

sed -i '/`grep -A 12 ".production ="`/d' file_a.txt

GNU sed way

In GNU sed (if you are using some Linux distribution it should be default sed implementation), you can use something like this:

sed '/.production =/,+12d' inputfile.txt

How it works:

  1. It scans the input file line by line (this is how sed works) and check if the command should be used.
  2. Our command is d (the last character) which means delete the line.
  3. But this command will only run if current line does match our range.
  4. The range is specified by two arguments (start and end of range, inclusive) delimited by , character. First is a regular expression /.production =/ which match each line containing this expression. Second argument is +12d which means 12 lines from start range.
  5. So our range matches each line that matches expression and next 12 lines and deletes them.
  6. All the other lines are printed to the output (default sed behaviour).

Portable, ugly way

This one should work on other sed implementation but involves much more typing and is not so robust:

sed '/.production =/{N;N;N;N;N;N;N;N;N;N;N;N;d}' somefile.txt

How it works:

  1. It scans the input file line by line (this is how sed works) and check if the command should be used.
  2. It checks if the line matches the /.production =/ pattern. If so, it runs all the commands in {} braces.
  3. We run N comamnd 12 times. N command reads next line and appends it to current buffer. So after we run it 12 times, we have 13 lines concatenated in current buffer (first line + 12 read by N commands).
  4. Now we run d command which deletes this concatenated 13 lines.
  5. sed continues until it finds another pattern and again deletes 13 lines. All the other lines are printed (default sed behaviour).
  • That's true, it worked perfectly fine, I didn't know this sed feature. Thanks. Oct 9 '12 at 10:25
  • Hi, guys, very thanks for the help; the first solution of manatwork works fine; thanks manatwork for the command: sed '/.production =/,+12d' inputfile.txt I register today on 3 Linux site, so I put my question 3 times; my apologies. I am new in all this Linux stuff and I will follow the advice of you and the advice of xenoterracide. So I will close on stackoverflow.com and move to unix.stackexchange.com I did not know that you guys (and your good knowledge) are presented on both internet sites. Also in the future I will ask my question on unix.stackexchange.com Again, very thanks
    – Clayton
    Oct 9 '12 at 12:21

You can retrieve the line number where you want to start filtering and than filter it witn AWK.

In AWK NR means the record number, by default its the end of line (\n).

START_LINE=$(cat file_a.txt | grep -n .production | cut -f1 -d:)
cat file_a.txt | awk '{ if(NR < '$START_LINE' || NR > '$START_LINE' + 12) print $0; }'

When grep and sed aren't quite cutting it, reach for awk. Awk can emulate most text utilities easily (sort being the main exception), and can combine them in more flexible ways than piping.

awk '
    /.production =/ {skip_lines = 13}
    skip_lines {--skip_lines}
    !skip_lines {print}
' file_a.txt >file_a.txt.new &&
mv file_a.txt.new file_a.txt

You can use Vim in Ex mode:

ex -sc '/.production =/d13|x' file_a.txt
  1. // move to matching line

  2. 13 select 13 lines

  3. d delete

  4. x save and close

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.