grep is not a programming language, it can't understand 'if x then do y'. It can't even remember lines for later. awk is a programming language, though, and can do both.
Perhaps something like
$ cat regafter.awk
# Recall N lines ago up to 9 lines
function last(N)
{
if(N>L) return("");
return(LINE[(L-N)%10]);
}
{ LINE[(++L)%10]=$0 } # Remember line for later
# If this line and the last line don't match titlex, print last line.
(last(1) ~ /title[^xX]/) && /title[^xX]/ { print last(1) }
# Do the same test for the last line by itself.
END { if(last(0) ~ /title[^xX]/) print last(0); }
$ awk -f regafter.awk data
titleA
titleC
titleE
$
NEVERMIND. THIS DOES NOT WORK CORRECTLY when titlex is the first line in the file or when there are consecutive instances of titlex. I leave it here only for your amusment.
Corona's awk solution is more efficient, since it only reads the data once, but here's a simple ed solution.
ed -s data <<EOED
g/titlex/-,.d
g/title/
Q
EOED
Or, if you prefer a less readable oneliner
printf %s\\n g/titlex/-,.d g/title/ Q | ed -s data
Thanks corona. If I want to substitute "titlex" with another string, how can I do that? In the code, I replaced "title[^xX]" with another string to test, but it outputs the new searched string.
# Recall N lines ago up to 9 lines
function last(N)
{
if(N>L) return("");
return(LINE[(L-N)%10]);
}
{ LINE[(++L)%10]=$0 } # Remember line for later
# If this line and the last line don't match titlex, print last line.
(last(1) ~ /TEST/) && /TEST/ { print last(1) }
# Do the same test for the last line by itself.
END { if(last(0) ~ /TEST/) print last(0); }
That string accepts TEST, it doesn't reject it. It even rejects titleA. It won't print things it doesn't accept. Given your input data, that's what I thought you wanted.
This should easily let you input an exact string to take as the string to reject.
$ cat regafter2.awk
# Recall N lines ago up to 9 lines
function last(N)
{
if(N>L) return("");
return(LINE[(L-N)%10]);
}
{ LINE[(++L)%10]=$0 } # Remember line for later
# If this line and the last line don't match titlex, print last line.
(last(1) != REJECT) && $0 != REJECT { print last(1) }
# Do the same test for the last line by itself.
END { if(last(0) != REJECT) print last(0); }
$ awk -v REJECT="TEST" -f regafter2.awk data2
titleA
$
I had trouble all the way through this thread understanding the requirements. I'll assume that followed with means immediately followed by. Here is a solution for the last sample:
% ./s2
Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution : Debian GNU/Linux 5.0.8 (lenny)
bash GNU bash 3.2.39
cgrep ATT cgrep 8.15
-----
Input data file data3:
titleA
titleB
TEST FILLER
titleC
TEST
-----
Results, title to TEST:
titleB
TEST FILLER
titleC
TEST
-----
Results, invert title to TEST:
titleA
The cgrep utility is non-standard, but very useful. See the URL for the source for anyone to compile and use.
Best wishes ... cheers, drl
( Edit 1: replaced wrong version of script. )
( Edit 2: correct minor typo )
I am flailing around trying to solve for you a problem, which you keep changing. If you would lay down exactly what you need to do plainly the first time, I could solve it once.
$ cat regafter3.awk
# Recall N lines ago up to 9 lines
function last(N)
{
if(N>L) return("");
return(LINE[(L-N)%10]);
}
{ LINE[(++L)%10]=$0 } # Remember line for later
# If this line and the last line don't match titlex, print last line.
(last(1) !~ REJECT) && $0 !~ REJECT { print last(1) }
# Do the same test for the last line by itself.
END { if(last(0) !~ REJECT) print last(0); }
$ awk -v REJECT="TEST.*" -f regafter3.awk data3
titleA
$