The regex you are using seems too complex to only match one charater in the middle, either a -
, a .
or an space. Why do you need [-.]?\s*?
. That reads: Match a -
or a .
(optionally (`?)) followed by space (well, really (from man pcrepattern): The default \s characters are now HT (9), LF (10), VT (11), FF (12), CR (13), and space (32)). Well, actually, several spaces in lazy mode (*?).
In my opinion, all it needs to be is [ .-]
simple, one character, either an space, a dot, or a dash. This regex:
(\d{5})[-. ](\d{6})
The best place to try (the only real way to learn regexes) is to go to regex101.com and try. Here I created an example of this post in detail (in pcre, yes).
You can see that in the replacement, what you are asking about, I placed this replacement:
(one:\1) (two:\2) (three:3)
And you can see that on each line the whole match, from the start of the regex to its end, but not the surrounding text, gets replaced with that string where \1
and \2
are converted to the captured values. One for each (...)
.
If you want to make the first (...)
non capturing, then there will be only one capturing group, and the replacement should change to:
(one:1) (two:\1) (three:3)
Only one \1
. Or else, the replacement will fail.
If you want to replace the whole line, make it match the whole line, from start to end:
^.*(?:\d{5})[-. ](\d{6}).*$
And make the replacement only \1
to print the last group of digits.
Now, about grep. Grep doesn't have replacements, there is something that "kind of" helps, but is not a good equivalent: \K
.
grep -Po '^.*\d{5}[-. ]\K\d{6}' file
One important idea to get is that -o
is intended to give out all that the regex matched, yes, the whole regex, not each matching parenthesis.
To work with a real replacement (or substitute (s///
)) you need sed
(but it uses BRE not PCRE):
$ sed 's/^.*\([0-9]\{5\}\)[-. ]\([0-9]\{6\}\).*$/ \2 \1 /' file
567890 01234
222111 01111
543210 09876
that does a real replacement and it allows to change the order (or to repeat).