How to get all lines between the one containing a certain string and another one containing another string PLUS the line before

Viewed 94

I've spent some time searching the web, but didn't find the answer. Let's say I have a file containing the following lines :

aaaaaaa
vvvvv
ggggg
yyyyyyyyy
ffffff
rrrrrrrr
uuuuu
ssssssssssss
zzzzz
hhhhhhhh

I know how to find all lines from the one containing "ffffff" to the one containing "uuuuu" using awk :

awk '/ffffff/,/uuuuu/' file

But how can I get also the line preceding the first one I found (i.e. "yyyyyyyyy")? Is there something like grep -B 1 to do this? What I want to get is :

yyyyyyyyy
ffffff
rrrrrrrr
uuuuu

Thanks in advance.

4 Answers

To only print if both ffffff and uuuuu exist in the input and not print a blank line if ffffff is the first line in the input:

$ cat tst.awk
/ffffff/ { f = 1 }
f {
    rec = rec $0 ORS
    if ( /uuuuu/ ) {
        printf "%s", rec
        f = 0
    }
    next
}
{ rec = $0 ORS }

$ awk -f tst.awk file
yyyyyyyyy
ffffff
rrrrrrrr
uuuuu

You may use this awk:

awk '/ffffff/ {flag=1; prev=p} flag {if (prev!="") print prev; prev=""; print} /uuuuu/ {flag=0} {p=$0}' file

yyyyyyyyy
ffffff
rrrrrrrr
uuuuu

a slight variation

$ awk '/fffff/{print p; f=1} f; /uuuuu/{f=0} {p=$0}' file

yyyyyyyyy
ffffff
rrrrrrrr
uuuuu

assumes begin/end markers don't overlap but can exist multiple times.

Explanation: Starting first fffff it will print the previous line (captured in p) and sets a flag. f; means print the current line if flag is set, shorthand for f==1{print $0}. Next statement resets the flag if uuuuu seen and finally we capture the line to be used in the first statement; this seems unnecessary all except one case it's used but most likely cheaper than comparing each time.

Note that this is probably the simplest script you can get with limited functionality to handle edge cases (multiple begin/end markers, no end marker etc).

Another awk using the loop for:

awk -v OFS='\n'  '{for (i=1; i<=NF; i++) if ($i == "ffffff"|| $i == "uuuuu") print p,$0} {p=$0}' file
yyyyyyyyy
ffffff
rrrrrrrr
uuuuu
  • or without for if there is only one field:
awk -v OFS='\n'  '{ if ($1 == "ffffff" || $1 == "uuuuu") print p,$0} {p=$0}' file
yyyyyyyyy
ffffff
rrrrrrrr
uuuuu
Related