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^[^\.][^\.]*\.[^\.]*\.[^\.][^\.]*$