views:

98

answers:

8

I have two queries

  1. I do a grep and get the line number of the input file. i want to retrieve a set of lines before and after the line number from the inputfile and redirect to a /tmp/testout file. how can i do it.

  2. I have a line numbers 10000,20000. I want to retrieve the lines between 10000 and 20000 of the input file and redirect to a /tmp/testout file. how can i doi it

+1  A: 

See head and/or tail.

For example:

head -n 20000 <input> | tail -n 10000 > /tmp/testout

whereas the argument of tail is (20000 - 10000).

ypnos
+1  A: 

If you're using GNU grep, you can supply -B and -A to get lines before and after the match with grep.

E.g.

grep -B 5 -A 10 SearchString File

will give print each line matching SearchString from File plus 5 lines before and 10 lines after the matching line.

For the other part of your question, you can use head/tail or sed. Please see other answers for details.

Brian Rasmussen
Only in GNU grep - POSIX grep does not include the '-A' or '-B' options. Since one tag is 'linux' you don't get a down vote, but since another tag is 'unix', I'm not sure about the up vote, either. Plus this only answers Q1, not Q2.
Jonathan Leffler
@Jonathan: Fair point and thanks for leaving a comment in any case. I didn't answer part two as that was already covered. I'll update the question to reflect that.
Brian Rasmussen
+2  A: 

You want to look into the -A -B and -C options of grep. See man grep for more information

   -A NUM, --after-context=NUM
          Print  NUM  lines  of  trailing  context  after  matching lines.
          Places  a  line  containing  --  between  contiguous  groups  of
          matches.

   -B NUM, --before-context=NUM
          Print NUM  lines  of  leading  context  before  matching  lines.
          Places  a  line  containing  --  between  contiguous  groups  of
          matches.

   -C NUM, --context=NUM
          Print  NUM lines of output context.  Places a line containing --
          between contiguous groups of matches.

For redirecting the output, do the following: grep "your pattern" yourinputfile > /tmp/testout

WakiMiko
A: 

For part 2, awk will allow you to print a range of lines thus:

awk 'NR==10000,NR==20000{print}{}' inputfile.txt >/tmp/testout

This basically gives a range based on the record number NR.

For part 1, context from grep can be obtained using the --after-context=X and --before-context=X switches. If you're running a grep that doesn't allow that, you can dummy up an awk script based on the part 2 answer above.

paxdiablo
`NR>=10000{print}NR>20000{exit}`
ghostdog74
A: 

to see the before and after: (3 lines before and 3 lines after)

grep -C3 foo bar.txt

the second question:

head -20000 bar.txt | tail -10000 > foo.txt
動靜能量
+8  A: 

for grep -C is the straight forward option

for the 2nd question try this!

sed -n "100000,20000p" bar.txt > foo.txt 
abubacker
As noted in a comment to another question, your answer only works with GNU grep - POSIX grep does not include the '-C' option (or '-A' or '-B' options).
Jonathan Leffler
A: 

you can do these with just awk, eg display 2 lines before and after "6", and display range from linenumber 4 to 8

$ cat file
1
2
3
4
5
6
7
8
9
10

$ awk 'c--&&c>=0{print "2 numbers below 6: "$0};/6/{c=2;for(i=d;i>d-2;i--)print "2 numbers above 6: "a[i];delete a}{a[++d]=$0} NR>3&&NR<9{print "With range: ->"$0}' file
With range: ->4
With range: ->5
2 numbers above 6: 5
2 numbers above 6: 4
With range: ->6
2 numbers below 6: 7
With range: ->7
2 numbers below 6: 8
With range: ->8
ghostdog74
A: 

If your grep doesn't have -A, -B and -C, then this sed command may work for you:

sed -n '1bb;:a;/PATTERN/{h;n;p;H;g;bb};N;//p;:b;99,$D;ba' inputfile > outputfile

where PATTERN is the regular expression your looking for and 99 is one greater than the number of context lines you want (equivalent to -C 98).

It works by keeping a window of lines in memory and when the regex matches, the captured lines are output.

If your sed doesn't like semicolons and prefers -e, this version may work for you:

sed -n -e '1bb' -e ':a' -e '/PATTERN/{h' -e 'n' -e 'p' -e 'H' -e 'g' -e 'bb}' -e 'N' -e '//p' -e ':b' -e '99,$D' -e 'ba' inputfile > outputfile

For your line range output, this will work and will finish a little more quickly if there are a large number of lines after the end of the range:

sed -n '100000,20000p;q' inputfile > outputfile

or

sed -n -e '100000,20000p' -e 'q' inputfile > outputfile
Dennis Williamson