10

I have a text file similar to this:

line 1
line 2A
line 3
line 4A
line 5

I want to "grep" from "line 2A" to the end of file, something like this

cat file.txt|some_grep "line 2A"

Also, I want to "grep" from "line 2A" to the next line that contains "A", something like this

cat file.txt| some_grep "A"

I want this to print out:

line 2A
line 3
line 4A

Which command can help me achieve this?

  • The first is the exact case that is trivial for awk range patterns awk '/line 2A/,0' and the second can be awk '/line 2A/,/A/&&!/line 2A/' or if it's at least one char before the A awk '/line 2A/,/[^2]A/' – dave_thompson_085 Jan 30 '16 at 10:09
  • Thank you, if you could turn this into an answer, I'll mark it as it as the...answer. – phong Feb 3 '16 at 15:49
4

(expanded from comment)

awk has a capability to select 'ranges' of lines which matches this need perfectly, as described in the the GNU-awk (gawk) manual. (This feature works in other awks but the gawk manual is easy to link.)

awk '/line 2A/,0' prints lines starting with the first one that matches line 2A and continuing until the end of input because 0 is a condition that is never true.

awk '/line 2A/,/A/&&!/line 2A/' starts printing with a line that matches line 2A and stops after a line that matches A but NOT line 2A (and thus cannot be the same line as the starting line). It will start again on a subsequent line 2A and so on; if you want to prevent that there are slightly more complicated ways to do so.

If the stopping lines always have some character other than 2 before the A this can be simplified to awk '/line 2A/,/[^2]A/' which stops after a line that matches any character other than 2, followed by A. You might want a variation of this, e.g. to stop on any-single-digit-A different from 2A, but not other As like WHAT; for that the stopping condition might be ,/line [013-9]A/.

| improve this answer | |
9

I want to "grep" from "line 2A" to the end of file:

sed -n '/2A/,$p'
  • -n : suppress sed default output
  • /2A/ : output lines from the first one containing "2A"
  • $ : to end of file

I want to "grep" from "line 2A" to the next line that contains "A":

sed -n '/2A/,/A/p'
  • /A/ : output until a line contains "A"

I want to "grep" from the first line containing "A" to the next one:

printf "/A\n.+1,/A/p\nq" | ed -s

$ > foo echo "line 1
line 2A
line 3
line 4A
line 5"

$ sed -n '/2A/,$p' foo
line 2A
line 3
line 4A
line 5

$ sed -n '/2A/,/A/p' foo
line 2A
line 3
line 4A

$ printf "/A\n.+1,/A/p\nq" | ed -s foo
line 2A
line 3
line 4A
| improve this answer | |
  • There is an hint in the question some_grep "A" which suggests OP wants smallest range of lines between two containing "A". Defining the range from /2A/ to /A/ is a specific case and a workaround rather than an answer. – techraf Jan 30 '16 at 10:42
  • @techrat I'm answering to the question that I quoted in my reply. Granted there is a contradiction with the parameter passed. Answer updated. – jlliagre Jan 30 '16 at 10:50
  • Unfortunately sed -n '/A/,/A/p' is a wrong answer. Try it with an input file with more than two lines containing "A". – techraf Jan 30 '16 at 10:54
  • @techraf Indeed, answer updated again. – jlliagre Jan 30 '16 at 11:10
3

I think the best way is to use grep in combination with cut and tail. First, use grep to get the line on which the desired string is (-n to output line number; -m 1 to stop searching after the first match):

grep -n -m 1 "somestring" filename.txt

This outputs the line number and the string itself. To cut away the string, we use cut (-f1: output first field; -d: use ":" as delimiter):

grep -n -m 1 "somestring" filename.txt | cut -f1 -d:

Next, we use the output of this command as parameter in tail. Normally, tail prints the last k lines, but using -n +k, we get tail to print from line k onwards. The total command is:

tail -n +`grep -n -m 1 "somestring" filename.txt | cut -f1 -d:` filename.txt

To output the lines until somestring use head instead of tail and -n -# instead of -n +#. You could also combine both to get the lines from one string until another.

| improve this answer | |
0

Please try the code below -

sed -n '6,$p' infile
| improve this answer | |
  • 3
    Can you turn this into a "teachable moment" by expanding your answer to explain the command? Thanks. – fixer1234 Jan 30 '16 at 10:05
  • 1
    This ignores conditions specified by OP in first and (even after modification) does not answer the second problem: from "line 2A" to the next line that contains "A". – techraf Jan 30 '16 at 10:15
0

The sed method is the way to go, but what if you want to keep the top lines, but not grep them?

Here's a way:

{ head -1 file.txt ; sed 1d file.txt | grep <whatever> ;}

What's going on here?

First, we spit out the top line (head -1 file.txt) Then, we remove the top line (sed 1d file.txt) and grep just that.

The whole thing is wrapped by { .. ;}, so you can pipe or redirect both the header and the grepped body together afterward. Like this:

{ head -1 file.txt ; sed 1d file.txt | grep ;} > newfile.txt

If you want to skip the first 10 lines, change it to this

{ head -10 file.txt ; sed 1,10d file.txt | grep ;}

| improve this answer | |

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.