I know that I can use grep to search for a string. But what if I want the output to show only lines where the string I search for occurred more than once? I prefer grep.

To clarify, I need to print the lines where the keyword appears more than once (i.e. two or above, or at least two). But I do not mean the lines that have exactly two.


If the search string can occur anywhere on the line, you could could do grep 'str.*str' for at least two matches.

And if you want to match the string multiple times, e.g. at least three times, you could do grep '\(.*str\)\{3\}'.

  • Yes, that's what I thought as OP said he/she was "searching for a string". But I'm not so sure any more... – Freddy Jul 17 '19 at 17:53

So, you need to match lines that have an string (at least) "two times".

  1. That's (with backreferences):

    $ str="string to match";     grep '\('"$str"'\).*\1' file

    Assuming that str is an string that avoids regex structures (or they are correctly quoted to avoid them being interpreted as a regex). Of course, str could be a regex, but it will match an string, the first one, and check for repeats of that string, not generic regexes. That is: str=h[aeiou]t will not match aaa hot bbb hit cccc, only hit bbb hit.

  2. Or (with generic regexes (probably faster)):

    str="string or regex to match";       grep '\(.*'"$str"'\)\{2\}' file

    where the number 2 could be replaced by any count easily (four or more here):

    str="regex to match"; n=4;            grep '\(.*'"$str"'\)\{'"$n"'\}' file

    That is: this will match hat het hit hot hut or hat hat hat hat

    str='h[aeiou]t'; n=4;                 grep '\(.*'"$str"'\)\{'"$n"'\}' file
  • @ilkkachu Thanks for your downvote, much appreciated. – Isaac Jul 19 '19 at 17:54

It's impossible to search for 2 or more occurrences of a string in a line using grep since you'd need to use regexp constructs to join the "strings" and then the strings are no longer strings, they're regexps. You need to use awk instead, e.g. to find 2 or more ocurrences of the string .*:

$ echo 'foo.*bar' | awk -v str='.*' '(s=index($0,str)) && index(substr($0,s+length(str)),str)'
$ echo 'foo.*bar.*etc' | awk -v str='.*' '(s=index($0,str)) && index(substr($0,s+length(str)),str)'
  • 1
    Dear drive-by downvoter - if you don't understand why this is the correct answer then please just ask and I'll be happy to clear up your confusion. – Ed Morton Jul 18 '19 at 7:11
  • What's wrong with echo $'foo.*bar\nfoo.*bar.*etc' | grep '\(\.\*.*\)\{2\}'. That will match exactly an string of .*, twice, properly quoted to be used as a regex. – Isaac Jul 19 '19 at 18:00
  • @Isaac What's wrong is that it's matching on a regexp and so you had to manually escape the regexp metacharacters to try to get it to act as it it were a string. That's a non-trivial task in general (see stackoverflow.com/q/29613304/1745001 for how you'd need to pre-process str in your answer before your calls to grep to get it to work when str contains RE metachars) and is convoluted thinking - if you want to find a string then use string constructs and if you want to find a regexp then use regexp constructs. – Ed Morton Jul 19 '19 at 19:23
  • OP specifically said "keyword" (see second para of question). Normally, one does not then use .* as an example. – sitaram Jul 21 '19 at 17:03
  • @sitaram that's a very naive interpretation of the requirements. The OP specifically said she wanted to search for a string - assuming a "keyword" cannot contain RE metachars and so you can use a regexp as if it were a string is a good way to inject insidious bugs in your code, bugs that may not show up during initial testing when the sample input doesn't contain RE metachars or they don't happen to match incorrectly but then bite you later when run on the real data. – Ed Morton Jul 21 '19 at 17:11

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.