3

I have a long list of strings separated by newlines and each section separated by a string starting with ~ (there are no other ~ in the file). I want to extend grep to find the ~ text right below the match.

Input:

abc
ads
acb
abc
acsa
acfs
~notthis
abc
ads
acb
xyz                <-- pattern
acsa
acfs
~this              <-- output
abc
ads
acb
abc
acsa
acfs
~no

Output when searching for xyz:

~ this

With awk I'd do something like

awk '/xyz/{x=1}x&&/~/{print;exit}' file

but I want to use grep if it can give me a performance advantage

2 Answers 2

4

At least with GNU grep 2.12:

$ grep -Pzo 'xyz(?:.*\n)*?\K~this' file
~this

If your grep version does not allow -P with -z, you can use pcregrep instead:

$ pcregrep -Mo 'xyz(?:.*\n)*?\K~this' file
~this
10
  • 1
    Thanks, but I get grep: The -P and -z options cannot be combined with GNU grep 2.5.2. Also, I don't know the text after ~ like you searched for ~this- this is my desired output (I only know it's following a ~)
    – confused00
    Oct 29, 2014 at 10:30
  • I replaced ~this in your pattern with .* and I get the right output, thanks. Do you know whether there's a performance disadvantage for using pcregrep instead of grep?
    – confused00
    Oct 29, 2014 at 10:38
  • 1
    I have a hard time to believe it is working. If one can use ~this literally then simple grep '~this' file will do the job, but this is not the point, right? To my mind it should be pcregrep -Mo 'xyz[^~]*?\K~.*' file | head -1. Also I don't believe any kind of grep expression can beat awk.
    – jimmij
    Oct 29, 2014 at 11:25
  • 1
    And after replacing ~this to .* does it work as expected for you, i.e. returns ~this? My version of pcregrep returns ~no two times, what is understandable due to greedy nature of *, so one has to at least add ? after *.
    – jimmij
    Oct 29, 2014 at 11:42
  • 1
    Test once again more carefully, most probably it matches many occurrences of the pattern, and you want only first, right?
    – jimmij
    Oct 29, 2014 at 12:06
1
cat "$file" | grep xyz -A 10000 | grep \~ -m1

or, equivalently,

grep -A 10000 xyz "$file" | grep -m1 '~'
3
  • This looks like it will produce the correct output, but I wonder whether it really performs better (i.e., runs faster) than awk. Have you tested that? Please post your benchmark results. Jun 30, 2022 at 17:08
  • I have not benchmarked it but I found a link that says, basically, since awk has more to do per line that grep is faster unix.stackexchange.com/questions/88503/using-grep-vs-awk Jul 4, 2022 at 5:57
  • Well, yeah, but the OP’s suggested command runs one awk process, and your answer runs two grep processes.  So this raises the question: how much faster is grep than awk?  Twice as fast?  Also, the OP’s command exits immediately upon finding the desired match, whereas yours potentially goes 9999 lines beyond it. Jul 4, 2022 at 22:15

You must log in to answer this question.

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