5

I have a text file, fred.txt:

% cat -e fred.txt 
00:$
00:04:$
01:00:23:34$
01:$
01:40:$
01:40:32:$
%

I can grep for a line with 2 digits and a colon:

% pcregrep -e '[\d]{2}:' fred.txt   
00:
00:04:
01:00:23:34
01:
01:40:
01:40:32:
%

but when I try to get repeating patterns of that pattern, it doesn't find them:

% pcregrep -e '[[\d]{2}:]{2}' fred.txt
%

I'm looking to get the same output as this:

% pcregrep -e '[\d]{2}:[\d]{2}:' fred.txt
00:04:
01:00:23:34
01:40:
01:40:32:
%

Eventually I'll be looking for more nested repeating patterns in a larger file so I don't want to define each time the pattern repeats. How do I grep for the lines that have that pattern repeating?

2
  • 7
    I think you're confused by the brackets. There's no point in [\d], that's the same as \d. The [ ] are used to define a character class, but \d is already a character class so you don't need to put it in [ ] unless you combine it with something else like [\dabc]. Then, as shown by schrodigerscatcuriosity's answer, you group things with parentheses (foo){2} and not square brackets [foo]{2}.
    – terdon
    Feb 2, 2022 at 18:42
  • That’s what I didn’t understand. Most of my complex regex use has been in Sublime Text so I’m not proficient outside of that. Thanks! Feb 2, 2022 at 19:35

3 Answers 3

12

Using GNU grep

$ grep -Eo '([0-9]{2}:){2,}' fred.txt 
00:04:
01:00:23:
01:40:
01:40:32:
0
7

[xyz] called bracket expressions is to match one character within a set. Here, either x, y or z.

[\d] would match either \ or d in POSIX basic regexps, but in perl-compatible regexps, it matches the same as \d alone: a digit. That allows things like [\da-fA-F] to match one hex digit for instance, but in the [\d] case, it's pointless, as you might as well use \d.

In any case, it's not for grouping for which you need \(...\) in POSIX basic regexps or (...) in POSIX extended regexps or PCREs.

PCREs have a few other variants of grouping such as (?:...) which groups without creating a back-reference, or (?|...) which groups but affects how back-references are numbered in alternations, or (?>...) the possessive variant of the grouping operator, etc.

Here, you don't need backreferences, so you might as well use (?:...):

pcregrep '(?:\d{2}:){2}'

Would match on lines that contain 2 of (2 digits followed by a :). If you wanted to match on lines that are exactly that, you'd need to add the -x option.

Here,

pcregrep '(?:\d\d:){2}'

Would actually be shorter.

pcregrep '(\d\d:){2}'

Would have the same effect, but possibly be slightly less efficient as we didn't tell pcregrep not to bother capturing what's inside the (...).

See man pcrepattern to learn more about the syntax of PCREs.

5

Using grep

$ grep -Eo '([^:]*:[[:digit:]]+:?)+' input_file
00:04:
01:00:23:34
01:40:
01:40:32:

You must log in to answer this question.

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