You're not saying how the string is input from the user, but note that if it may contain newline characters, you can't use grep
to filter them (unless you use the --null
extension) as grep
works on one line at a time. Also note that the [^\.]
regex matches on characters other than backslash and .
and the .
regex operator (or [...]
) in many regex implementations will not match on bytes that don't form valid characters in the locale.
Here, to check that $string
contains 2 and only 2 dots, but not at the start nor end and not next to each other, you can use the standard sh
:
case $string in
(*.*.*.* | .* | *. | *..* ) echo not OK;;
(*.*.*) echo OK;;
(*) echo not OK;;
esac
Or with ksh globs, a subset of which can be made available in the bash shell by doing shopt -s extglob
:
case $string in
( +([!.]).+([!.]).+([!.]) ) echo OK;;
(*) echo not OK;;
esac
bash
can also do extended regex matching with the =~
operator inside its [[...]]
ksh-style construct, but again, you'll want to fix the locale to C:
regex_match_in_C_locale() {
local LC_ALL=C
[[ $1 =~ $2 ]]
}
if regex_match_in_C_locale "$string" '^[^.]+\.[^.]+\.[^.]+$'; then
echo OK
else
echo not OK
fi
POSIXly, you can do basic regex matching with the expr
utility:
if
LC_ALL=C expr "x$string" : 'x[^.]\{1,\}\.[^.]\{1,\}\.[^.]\{1,\}$' > /dev/null
then
echo OK
else
echo not OK
fi
Or extended regex matching with the awk
utility:
regex_match_in_C_locale() {
LC_ALL=C awk -- 'BEGIN {exit(ARGV[1] !~ ARGV[2])}' "$@"
}
if regex_match_in_C_locale "$string" '^[^.]+\.[^.]+\.[^.]+$'; then
echo OK
else
echo not OK
fi
abc.def.xyz
?*
means zero or more. Change your RE to^[^\.][^\.]*\.[^\.]*\.[^\.][^\.]*$