#=== FUNCTION ================================================================ # NAME: range_parse # DESCRIPTION: Parse a comma-separated list of numbers and "number-number" # ranges such as '1,3,5-7,9' # PARAMETERS: 1 - maximum limit of the range # 2 - entered range expression (e.g. 1-3,7,14) # 3 - name of the variable to receive the result # RETURNS: Writes a list of values to the nominated variable and returns # 0 (true) if the range parsed, and 1 (false) if not #=============================================================================== function range_parse { local max=${1?range_parse: arg1 missing} local range=${2?range_parse: arg2 missing} local -n result=${3?range_parse: arg3 missing} local item selection sel err msg exitcode=0 # # Remove spaces from the range # range=${range// /} # # Check for invalid characters # if [[ $range =~ [^0-9,-] ]]; then echo "Invalid range: $range" return 1 fi # # Slice up the sub-ranges separated by commas and turn all n-m expressions # into the intermediate values. Trim the trailing space from the # concatenation. # until [[ -z $range ]]; do # # Get a comma-separated item # if [[ $range =~ [,] ]]; then item=${range%%,*} range=${range#*,} else item=$range range= fi # # Look for a 'number-number' expression # if [[ $item =~ [-] ]]; then if [[ $item =~ ^([0-9]{1,})-([0-9]{1,})$ ]]; then item=$(eval "echo {${item/-/..}}") else echo "Invalid sequence: ${item}" item= exitcode=1 fi fi selection+="$item " done # # Check for out of bounds problems, sort the values and and make unique # if [[ -n $selection ]]; then # # Validate the resulting range # for i in $selection; do if [[ $i -lt 1 || $i -gt $max ]]; then err+="$i " else sel+="$i " fi done # # Report any out of range errors # if [[ ${err+"${err}"} ]]; then msg="$(for i in ${err}; do echo "$i"; done | sort -un)" msg="${msg//$'\n'/ }" printf "Value(s) out of range: %s\n" "${msg}" exitcode=1 fi # # Rebuild the selection after having removed errors # selection= if [[ ${sel+"${sel}"} ]]; then selection="$(for i in ${sel}; do echo "$i"; done | sort -un)" selection="${selection//$'\n'/ }" fi fi # # Return the result # result="$selection" return $exitcode }