15

I want to show all lines before a match, not only 10, or 7, or 14 for example, as explained in How do I fetch lines before/after the grep result in bash?.

How can I do it? It doesn't matter if the matched line is included or not.

For example, instead of:

... | grep -B 10 -- "foo"

I want:

... | grep -B -- "foo"

But this last code doesn't work.

1
  • When I have published a reply in this topic: https://askubuntu.com/questions/1277701 i have received this comment: Edit your Q instead. – bac0n Sep 25 at 13:02 Make up your minds on what is best to do. Oct 22, 2020 at 20:34

7 Answers 7

23
  • Including the match,

    sed '/foo/q' file
    

    It is better to quit sed as soon as a match is found, otherwise sed would keep reading the file and wasting your time, which would be considerable for large files.

  • Excluding the match,

    sed -n '/foo/q;p' file
    

    The -n flag means that only lines that reach the p command will be printed. Since the foo line triggers the quit action, it does not reach p and thus is not printed.

    • If your sed is GNU's, this can be simplified to

      sed '/foo/Q' file
      

References

  1. /foo/Addresses
  2. q, pOften-used commands
  3. QGNU Sed extended commands
  4. -nCommand-line options
6
  • 4
    With GNU sed, there's also Q to quit without default-printing the matched line Oct 18, 2020 at 12:51
  • there is the perl alternative? Is more kind. Oct 18, 2020 at 14:52
  • 2
    @MarioPalumbo perl -pe 'exit if /foo/'; similarly awk '/foo/{exit} 1' Oct 18, 2020 at 15:04
  • 1
    @steeldriver you are genius. Your reply is the V green reply. Comment this as answer Oct 18, 2020 at 15:07
  • Can i have an example of OS with no-GNU sed? Oct 22, 2020 at 20:18
9

With GNU sed. Print all lines, from the first to the line with the required string.

sed '0,/foo/!d' file
1
  • This worked even with pipefail set, where q caused problems for me. Thank you!
    – metanerd
    Sep 26, 2023 at 9:13
5

Here's a solution with sed, given the content of file.txt:

bar
baz
moo
foo
loo
zoo

command including pattern

tac file.txt | sed -n '/foo/,$p' | tac

output

bar
baz
moo
foo

excluding pattern

tac file.txt | sed -n -e '/foo/,$p' | tac | sed -n '/foo/!p'

bar
baz
moo
3
  • What is tac? Perhaps cat? Oct 18, 2020 at 14:36
  • 4
    tac is a reverse cat ;) Oct 18, 2020 at 14:37
  • 2
    Wow. I've been using UNIX off-&-on (mostly on) for almost 30 years, & never heard of "tac" before today. There's always something new to learn.
    – llywrch
    Oct 19, 2020 at 15:36
4

To print all lines before the match,

perl -pe 'exit if /foo/' file
awk '/foo/{exit} 1' file
4

FreeBSD (including MacOS) version does have such feature.

Well -B -1 works, it shows all the lines before the match from the beginning of the file.

... | grep -B -1 -- "foo"

Same for -A -1 , it shows all the lines after the match to the end of the file.

... | grep -A -1 -- "foo"

May be useful for some, It doesn't work with GNU implementation included within Ubuntu.

2
  • 2
    It would be great if they introduced this feature to Ubuntu/Debian as well. Oct 22, 2020 at 20:58
  • @MarioPalumbo , That would be great. I even hope to the hole tool copied both side as extra gnu_* tools on BSD and bsd_* tools on GNU. But it seems hard due to old history of licensing.
    – user.dz
    Oct 23, 2020 at 7:01
3

Current solutions except schrodigerscatcuriosity's print the file contents even when there's no match. schrodigerscatcuriosity's involves using tac and so requires reading the whole input before looking for matches.

Here's another way to do it with just sed and printing only when there's a match:

sed -n '1h;1!H;/foo/{g;p;q}'
  • 1h -- copy pattern space to hold space when on the first line
  • 1!H -- append pattern space to hold space when not on the first line
  • /foo/{...} -- on matching /foo/,
    • g -- copy hold space to pattern space
    • p -- print pattern space
    • q -- quit
1
  • 1
    For huge files (a large fraction of your total RAM), if you aren't sure a match exists you might just grep -q input.txt && sed '/pattern/q input.txt to verify a match before running sed. Or get the line number from grep and use it for head. Slower than 1-pass when a match does exist, unless it means you avoided swap thrashing. Also doesn't work as a filter; needs to reopen its input from the start. Oct 19, 2020 at 7:33
3

Show ALL lines before a match

You can use large enough number for -B option of grep. For example if your know that input size is no more than 999 you can use it with -B option:

... | grep -B 999 -- "foo"

You must log in to answer this question.

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