This is one way to process it purely with Bash as required. No awks, sed and other stuffs.
#!/bin/bash
shopt -s extglob
IFS=,
while read -r LINE; do
OUTPUT=()
while [[ -n $LINE ]]; do
case "$LINE" in
+([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]))
OUTPUT[${#OUTPUT[@]}]=$LINE
break
;;
+([[:digit:]]).+([[:digit:]]).+([[:digit:]]).+([[:digit:]]),*)
OUTPUT[${#OUTPUT[@]}]=${LINE%%,*}
LINE=${LINE#*,}
;;
+([[:digit:]]).+([[:digit:]]).+([[:digit:]]).\[+([[:digit:],-])\]*)
SET=${LINE%%\]*}
PREFIX=${SET%%\[*}
read -a RANGES <<< "${SET:${#PREFIX} + 1}"
for R in "${RANGES[@]}"; do
case "$R" in
+([[:digit:]]))
OUTPUT[${#OUTPUT[@]}]=${PREFIX}${R}
;;
+([[:digit:]])-+([[:digit:]]))
X=${R%%-*} Y=${R##*-}
if [[ X -le Y ]]; then
for (( I = X; I <= Y; ++I )); do
OUTPUT[${#OUTPUT[@]}]=${PREFIX}${I}
done
else
for (( I = X; I >= Y; --I )); do
OUTPUT[${#OUTPUT[@]}]=${PREFIX}${I}
done
fi
;;
esac
done
LINE=${LINE:${#SET} + 2}
;;
*)
# echo "Invalid token: $LINE" >&2
break
esac
done
echo "${OUTPUT[*]}"
done
For an input of
192.168.38.[217,222],192.168.40.215,192.168.41.[219-222]
Running bash temp.sh < temp.txt yields
192.168.38.217,192.168.38.222,192.168.40.215,192.168.41.219,192.168.41.220,192.168.41.221,192.168.41.222
It's consistent also with ranges. If X is later than Y e.g. 200-100 then it would generate IPS with subsets of 200 to 100. The script could also process multi-line inputs.
And it should also work with mixed ranges like [100,200-250].