If you want to match on a sequence of 1 to 3 whitespace characters not surrounded by whitespaces, that's where you'd use Perl look-around operators:
grep -P '(?<!\s)\s{1,3}(?!\s)'
It matches on:
1
1234567890123456789
a b c d e
^ ^^ ^^^
With standard grep
, you could achieve the same effect with:
grep -E '(^|[^[:space:]])[[:space:]]{1,3}([^[:space:]]|$)'
This time we match on the sequence of 1 to 3 whitespace characters and the non-whitespace on either side (or the start (^
) or end ($
) of the subject).
1
1234567890123456789
a b c d e
^^^^ ^^^^
(with -o
(a GNU extension), you'd find it doesn't report a b
as a
was already matched earlier; when searching for more matches, it starts at the next character after the last match).
Without -E
, you get basic regexps that don't have alternation operators (though some grep
implementations support \|
for that as an extension), but standardly, you could still do:
grep -x '\(.*[^[:space:]]\)\{0,1\}[[:space:]]\{1,3\}\([^[:space:]].*\)\{0,1\}'
This time, the regexp matches the whole line including the 1 to 3 spaces and an optional (\{0,1\}
the equivalent of ERE ?
) leading part to it ending in a non-whitespace and an optional part following it that starts with a non-whitespace.
1
1234567890123456789
a b c d e
^^^^^^^^^^^^^^^^^^
In any case, those would still return lines that contain a sequence of 4 or more whitespaces as long as they also contain a sequence of 1 to 3 whitespace not surrounded by whitespaces.
If the point was to exclude lines containing sequences of 4 or more whitespaces then it would just be:
grep -vE '[[:space:]]{4}'
Or if you still require at least one whitespace, or in other words that the line contains one or more sequences of whitespace characters all of which have at least one whitespace but no more than 3:
grep -vE -e '[[:space:]]{4}' -e '^[^[:space:]]*$'
That is return all the lines except the ones that contain a sequence of 4 whitespace and the ones that are made exclusively of non-whitespaces.
Or again with Perl's look around operators:
grep -P '^(?=.*\s)(?!.*\s{4})'
That is match the beginning of the line, provided that it's followed by any amount of characters and a whitespace and that it's not followed by any amount of characters and a sequence of 4 whitespace.
Though it would be more legible with sed
or awk
where you can do both a positive and negative match in the same invocation:
awk '/[[:space:]]/ && ! /[[:space:]]{4}/'
sed '/[[:space:]]/!d; /[[:space:]]\{4\}/d'
echo aaaa | grep 'a'
works. Or, with extended (not PCRE) regular expressions and a specific number:echo aaaa | grep -E 'a{1,2}'
. The braces mean "I need to find this many characters". Whether or not there are also more after or before the braces is irrelevant.