grep - regex that will find exactly 3 a's in a string
Here's one way with [^a]
(match any character other than a
) instead of .
(match any character):
$ grep -E '^([^a]*a){3}[^a]*$' /usr/share/dict/cracklib-small | shuf -n 4
areaway
humanitarian
capitalizations
autonavigator
You can also write the regexp like ^[^a]*(a[^a]*){3}$
with the same results.
It's also equivalent to ^[^a]*a[^a]*a[^a]*a[^a]*$
which doesn't scale when you want a different number of a's. Performance is much better though, not that it matters unless you're grepping through gigabytes of data.
Instead of explicitly using the ^
and $
regexp anchor operators, you can also use the -x
option which does that implicitly. See also the -i
option to match case insensitively (according to locale):
grep -xiE '([^a]*a){3}[^a]*'
Use the same sort of pattern to detect "at least 4 a
s", and invert the sense of the match:
grep 'a.*a.*a' /usr/share/dict/words | grep -v 'a.*a.*a.*a'
or,
grep '\(a.*\)\{3\}' /usr/share/dict/words | grep -v '\(a.*\)\{4\}'
or,
grep -E '(a.*){3}' /usr/share/dict/words | grep -v -E '(a.*){4}'
Alternatively, use awk
with a
as the field delimiter and count the fields:
awk -F a 'NF == 4' /usr/share/dict/words
(on lines with three a
s, there would be four fields)
Alternatively, use Perl's tr
operator to count the number of a
s on each line:
perl -ne 'print if (tr/a/a/ == 3)' /usr/share/dict/words
The operator returns the number of transliterations made, and we're replacing each a
with another a
, so the actual output would not be modified.