Find string1, when true find string2 in reverse direction

Hello,

This is a bit complicated for me.
My scenario in MyFile:

Search string1,
When string1 is found, grep the line containing string1 , go back over that line in upward direction and grep the first line containing string2 .

Here is an example:

MyFile

His email address alfredo@alfredo.ru
test1
test2
test3
testtt 11223344
test4
test5
His email address daniel@alfredo.ru
kkkk
ddd
ggg
www
qqq
testtt 55667788
His email address lucas@alfredo.ru
aaa
bbb
ccc
ddedd
eeeeeeee
ffffff

string1: testtt
string2: @

Expected output:

His email address alfredo@alfredo.ru
test 11223344
His email address daniel@alfredo.ru
test 55667788

Thanks in advance
Boris

You can solve this with sed or awk or perl or shell buitins.
Please show your attempts!

Hello MadeInGermany,
I read that question mark is used for reverse direction search but I have no more idea.
I just searched on multiple boards with "multiple string search" keyword for this but no luck.

Kind regards
Boris

Your directions didn't say anything about changing string1 to the string test in the output to be produced??? And, if we do the grep 's in the order you specified, the lines containing string1 should be printed before the lines containing string2. Why isn't the desired output:

testtt 11223344
His email address alfredo@alfredo.ru
testtt 55667788
His email address daniel@alfredo.ru

? Is your sample output wrong or are your directions wrong?

Hello Don,
That output is also acceptable, no worries.

Kind regards
Boris

You didn't mention your OS nor grep version, so chances are this will not work for you:

grep "@\|testtt" Myfile | grep -B1 testtt
His email address alfredo@alfredo.ru
testtt 11223344
His email address daniel@alfredo.ru
testtt 55667788

Dear Rudic,
Thanks for your warning.

Ubuntu 14.04
grep (GNU grep) 2.16

Kind regards
Boris

If you want to do it with one process instead of two (or if you don't like the separator lines that grep -B produces, you could also try ed or awk (written to match your original specification):

string1=testtt
string2=@
echo 'Following output from "ed" script:'
ed -s MyFile <<END
	g/$string1/.p\\
	?$string2?p
END
printf '\nFollowing output from "awk" script:\n'
awk '
$0 ~ string1 {
	print
	print saved
}
$0 ~ string2 {
	saved = $0
}' string1="$string1" string2="$string2" MyFile

which, with your sample input, produces the output:

Following output from "ed" script:
testtt 11223344
His email address alfredo@alfredo.ru
testtt 55667788
His email address daniel@alfredo.ru

Following output from "awk" script:
testtt 11223344
His email address alfredo@alfredo.ru
testtt 55667788
His email address daniel@alfredo.ru
1 Like

Many thanks Don!

kind regards
Boris

Alternatively:

 perl -ne '/testtt/ and print "$_$keep"; $keep=$_ if /@/' test.file
     5  testtt 11223344
     1  His email address alfredo@alfredo.ru
    14  testtt 55667788
     8  His email address daniel@alfredo.ru

or

perl -ne '/testtt/ and print "$keep$_"; $keep=$_ if /@/' test.file
     1  His email address alfredo@alfredo.ru
     5  testtt 11223344
     8  His email address daniel@alfredo.ru
    14  testtt 55667788
cat test.file
     1  His email address alfredo@alfredo.ru
     2  test1
     3  test2
     4  test3
     5  testtt 11223344
     6  test4
     7  test5
     8  His email address daniel@alfredo.ru
     9  kkkk
    10  ddd
    11  ggg
    12  www
    13  qqq
    14  testtt 55667788
    15  His email address lucas@alfredo.ru
    16  aaa
    17  bbb
    18  ccc
    19  ddedd
    20  eeeeeeee
    21  ffffff
1 Like

Dear Aia,
I am running the python script to produce a new output.
I will let Don and you know when it's done.

Kind regards
Boris

If you are using Python already why don't you do it on it?

import re

string1 = re.compile('@')
string2 = re.compile('testtt')
with open("test.file") as f:
    for line in f:
        if string1.search(line):
            keep = line.rstrip()
            continue
        if string2.search(line):
           print("{0}{1}".format(line, keep))

With awk

awk '$0~S1 {s1=$0} $0~S2 {print s1; print}' S1="@" S2="testtt" MyFile 

You can restrict the search to the first field $1 (as opposed to the full line $0):

$1~S2

Or even have a full field match

$1==S2

(Now am seeing that Don had the same solution in principal)

Dear Don and Aia,
Both gives the expected out.

Dear MadeInGermany,
$0~S2 is okay at my end but as it's not printing the @ line, $1~S2 or $1==S2 is not okay

Thank you million times...

Kind regards
Boris

With that version, I think the suggestion in post#6 should work.

Dear Rudic,
it works but not giving the correct answer.
Exception: There is no corresponding @ info for the first found testtt keyword.

Others are okay

Kind regards
Boris

Not with the sample data given in your post#1.

Dear Rudic,
I am sorry, my typo error during test.
That is okay now.

Kind regards
Boris