#!/usr/bin/env bash # # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)convert-number 3.3.1 16.03.2026 (c)2026 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be # error free and you will not be reimbursed for any damage it may cause. # #@ Convert Number String e.g. 2,3,5-7,9 into a sequential number string e.g. 002 003 005 006 007 009 #@ #@Usage: convert-number numberstr #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version : Displays the version of the script. #@ -p, --padding : Numbers are sorted and left padded with 0 (default padding is 3). #@ -x, --max : Maximal - useful if one calls script with e.g. "5-". #@ NumberStr: Can be a numer or a string e.g. "2,3,5-7,9" #@ #@Examples: #@ convert-number --max 8 2,5- #@ Displays "002 005 006 007 008" # # Exit codes: # 01: Unknown or wrong parameter. # 02: Invalid number # 03: Minimum is 1. # 04: Number is greater than max number. # 99: User interrupt. # # Update history: # # V 2.0.0 05.07.2019 New version # V 3.0.0 02.05.2020 Minor changes # V 3.0.1 11.06.2020 Using library # V 3.1.0 05.06.2023 New copyright # V 3.1.1 28.07.2024 Trapping ctrl-c # V 3.2.0 12.08.2024 New minor version # V 3.2.1 13.10.2024 Converted from tcsh to bash # V 3.3.0 19.01.2026 Revised with support of Claude Code # V 3.3.1 16.03.2026 Optimized: replaced backticks with $(); [ ] with [[ ]]; # echo|grep with [[ =~ ]]; UUOC removed; bash parameter expansion for tr # # Find executable bash library and source it lib=$(command -v lib.bash 2>/dev/null) if [[ -n "$lib" ]]; then source "$lib" else progdir=$(dirname "$0") if [[ -r "${progdir}/lib.bash" ]]; then source "${progdir}/lib.bash" else echo "Unexpected error: Unable to locate bash library 'lib.bash'." exit 1 fi fi # Preset numberstr="" maxnumber="" padding="3" # Check parameters: Loop until all parameters are used up while [[ $# -gt 0 ]]; do pname="${1}" case "$pname" in -v | --version) shift showversion=true ;; -h | --help) shift showhelp=true ;; -p | --padding) shift if [[ -n "$1" ]]; then padding="${1}" if [[ ! "$padding" =~ ^[0-9]+$ ]]; then errstr="Not a number: '$padding'." fi shift else errstr="Please specify a number after parameter '$pname'." fi ;; -x | --max) shift if [[ -n "$1" ]]; then maxnumber="${1}" if [[ ! "$maxnumber" =~ ^[0-9]+$ ]]; then errstr="Not a number: '$maxnumber'." fi shift else errstr="Please specify a number after parameter '$pname'." fi ;; *) shift if [[ "$pname" == -* ]]; then errstr="Unknown option '$pname'." else if [[ -z "$errstr" ]]; then if [[ -z "$numberstr" ]]; then # Remove spaces with bash built-in (no tr subshell) numberstr="${pname// /}" else errstr="Number string was already specified '$numberstr'. Unknown additional parameter: '$pname'." fi fi fi ;; esac done # Plausibility checks if [[ -z "$errstr" && -z "$numberstr" ]]; then errstr="Please give a number string like '2,3,5-7,9'." fi # Display help or error message DisplayHelp ### Main # Create empty scratchfile printf "" > "$scratchfile" # Replace commas with spaces using bash built-in (no sed subshell) numbers="${numberstr//,/ }" # Iterate over each number/range token for num in $numbers; do # Use bash regex to detect range pattern (no echo|grep subshell) if [[ "$num" =~ ^([0-9]*)[-]([0-9]*)$ ]]; then rstr1="${BASH_REMATCH[1]}" rstr2="${BASH_REMATCH[2]}" if [[ -n "$rstr2" ]]; then if [[ -z "$rstr1" ]]; then rstr1=1 fi seq -f "%0${padding}g" "$rstr1" 1 "$rstr2" >> "$scratchfile" else if [[ -n "$rstr1" && -n "$maxnumber" ]]; then seq -f "%0${padding}g" "$rstr1" 1 "$maxnumber" >> "$scratchfile" else exitcode=2 errormsg $exitcode "($progstr) String '$num' is not a valid number or expression." Cleanup exit $exitcode fi fi elif [[ "$num" =~ ^[0-9]+$ ]]; then printf "%0${padding}g\n" "$num" >> "$scratchfile" else exitcode=2 errormsg $exitcode "($progstr) String '$num' is not a valid number or expression." Cleanup exit $exitcode fi done # Avoid UUOC: redirect file directly into sort filemin=$(sort -u < "$scratchfile" | head -n 1) if (( 10#$filemin < 1 )); then exitcode=3 errormsg $exitcode "($progstr) Selection is less then min '1'." fi if [[ $exitcode -eq 0 ]]; then if [[ -n "$maxnumber" ]]; then filemax=$(sort -u < "$scratchfile" | taillastline) if (( 10#$filemax > 10#$maxnumber )); then exitcode=4 errormsg $exitcode "($progstr) Selection is greater then max '$maxnumber'." fi fi # Display result if [[ $exitcode -eq 0 ]]; then sort -u < "$scratchfile" fi fi # Cleanup and exit Cleanup exit $exitcode