2
[user@notebook ~]$ printf 'adgaa alpha lajsd assa ><>4 saf\n63SXYZae fkrk safXYZek\nsaf betf!%saa sDGFXYZFalf\n'
adgaa alpha lajsd assa ><>4 saf
63SXYZae fkrk safXYZek
saf betf!aa sDGFXYZFalf
[user@notebook ~]$ 
[user@notebook ~]$ printf 'adgaa alpha lajsd assa ><>4 saf\n63SXYZae fkrk safXYZek\nsaf betf!%saa sDGFXYZFalf\n' | grep SOMEMAGIC
63SXYZae fkrk safXYZek
[user@notebook ~]$ 

Question: how can I grep for only those lines that has a given string twice? In this example the string was "XYZ". Between the two strings, there could be anything.

  • Clarify please? – DisplayName Mar 6 '15 at 16:07
  • How to know which string you are looking for that occurs twice? – heemayl Mar 6 '15 at 17:17
  • 1
    What's wrong with grep 'PATTERN.*PATTERN' or, if the PATTERN is complex, P='PATTERN' grep "$P.*$P" ? – Adam Katz Mar 7 '15 at 0:56
  • @AdamKatz - the problem - as i see it - is that a PATTERN is not a match - the PATTERN might match any of several strings in several contexts – mikeserv Mar 7 '15 at 9:09
2

Grepping twice wouldn't bring you any benefit. I'd go for using egrep in combination with a regex that matches you need.

ps ax | egrep '(a.*){2}'

That would give you all processes, that have the 'a' twice. You can of course use that on any kind of input egrep can read.

  • 1
    Your pattern is wrong; it doesn't match all names with duplicates. To me (a.*){2} looks more reliable as a general ERE pattern to check a duplicate. – Janis Mar 6 '15 at 17:14
  • You're correct. The result of my RegEx just looked right at first sight to me, but your's is actually working as requested. I've edited the answer accordingly. – Daniel Mar 6 '15 at 18:28
  • This sort of regex is expensive, approaching a ReDoS because there are so many possibilities to match given a string with lots of the letter a in it. – Adam Katz Mar 7 '15 at 0:55
  • @Janis - your pattern is wrong. You don't match a string followed by itself - you match two successive strings which match the same pattern. – mikeserv Mar 7 '15 at 6:09
  • @mikeserv, I don't think so. The pattern in the example contains the sample strings "a", followed by an arbitrary string, and again by the same, thus you match the constant string pattern twice. That was exactly the requirement of the question; "a given string twice". – Janis Mar 7 '15 at 10:42
0

With regular expressions you can either back-reference a (grouped pattern)or you can specify that a match must {repeat} it. The difference between one and the other is significant. For a simple example consider the string:

baa

... when matched against the following two patterns:

\([ba]\)\{2\}
\([ba]\)\1

For the first of these the grouping is actually irrelevant because the pattern searches for a single character - when specifying repetitions the the grouping is only important in that it can contain a whole subexpression to which the repetition can refer. And so, for this simple example case...

 [ba]\{2\}

... and ...

\([ba]\)\{2\}

...are synonymous and can be taken to mean that the match engine should look for the leftmost and longest string in input that is composed of two characters - either of b or a. The repetition applies to the pattern which makes the match and not to the contents of the match. So it literally means:

[ba][ba]

....in the same way...

\(a.*\)\{2\}

...means...

a.*a.*

...which would work ok for the single character a but which is not a good example of how to match a matched string a second time.

For our input sample this gets...

ba

But the back-reference is very different - it is a reference to the content of the match. The simple example case gets...

aa

...because that is the leftmost and longest string in input that is comprised of a character that matches the subexpression's [ba] pattern and which is immediately followed by itself - not the pattern which matched the character.

So you want:

\(pattern\).*\1

Because a regular expression pattern and the string which it matches are not the same - else we wouldn't have much call to use regular expressions in the first place. To demonstrate the difference with a slightly more complicated input example consider the following:

printf %s\\n 123ABC321 123ABC123 321ABC321 |
grep '\([123]\{3\}.*\)\{2\}'

The grep above will print:

123ABC321
123ABC123
321ABC321

...because in every case the pattern is successfully matched twice. But if the grep line were replaced with:

grep '\([123]\{3\}\).*\1'

... it would only print ...

123ABC123
321ABC321
  • With [] you're using character classes. I might be wrong, but I was under the impression, that you can't do [test] (notice the double t) with character classes. Hence, you can't search for an exact string that way. – Daniel Mar 7 '15 at 10:47
  • @Daniel - No - a character class matches a character as a part of a pattern - you're right that you cannot match a fixed string within a character class except that the string is a single char and the class is comprised only of it. What you can do is match a pattern, group it, and back-reference the match - and so match the match a second time rather than the pattern - that's the point of this answer. It allows you to more freely compose your search pattern as you are not limited to fixed strings in your pattern and can yet rely on the identical first/second matches. Use grep -F for fixed. – mikeserv Mar 7 '15 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.