Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash, prompt for numerical input

d is an internal server lookup tool I use.

I am looking to allow a user to input any number between 0 (or 1) and 9999 (let's call this userinput) and have it display the result of:

d $userinput (e.g. 1234)

Then manipulate the results of that lookup (below gets rid of everything but the IP address to ping later):

 grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'`

I know I need to use the while true; do read $blah etc etc. I am just not familiar with read enough to format it properly and more importantly:

get it to prompt for a numerical input between 0-9999

like image 347
Zippyduda Avatar asked Nov 19 '25 01:11

Zippyduda


2 Answers

The other answers have many flaws, because they check that the user didn't input a number outside of the range they want. But what if a user enters something that is not a number? their strategy is broken from the start.

Instead it's better to let go only when we're sure that the user entered a number which lies within the wanted range.

while :; do
    read -ep 'Enter server number: ' number
    [[ $number =~ ^[[:digit:]]+$ ]] || continue
    (( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) || continue
    # Here I'm sure that number is a valid number in the range 0..9999
    # So let's break the infinite loop!
    break
done

The regex [[ $number =~ ^[[:digit:]]+$ ]] makes sure that the user only entered digits.

The clumsy (number=(10#$number)) part is here so that if the user enters a number that starts with a 0, bash would try to interpret it in radix 8 and we'd get a wrong result (e.g., if the user enters 010) and even an error in the case when a user enters, e.g., 09 (try it without this guard).


If you only want to prompt once and exit when the user inputs invalid terms, you have the logic:

read -ep 'Enter server number: ' number
[[ $number =~ ^[[:digit:]]+$ ]] || exit 1
(( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) || exit 1
# Here I'm sure that number is a valid number in the range 0..9999

If you want to explain to the user why the script exited, you can use a die function as:

die() {
    (($#)) && printf >&2 '%s\n' "$@"
    exit 1
}
read -ep 'Enter server number: ' number
[[ $number =~ ^[[:digit:]]+$ ]] ||
    die '*** Error: you should have entered a number'
(( ( (number=(10#$number)) <= 9999 ) && number >= 0 )) ||
    die '*** Error, number not in range 0..9999'
# Here I'm sure that number is a valid number in the range 0..9999
like image 82
gniourf_gniourf Avatar answered Nov 21 '25 22:11

gniourf_gniourf


<--edit-->

if all you want is the mechanic for prompting, try this:

echo -n "Enter server number:"
read userinput

then run validation checks on the input like this:

if [[ $userinput -lt 0 || $userinput -gt 9999 ]]   # checks that the input is within the desired range
 then
  echo "Input outside acceptable range."
else
  # insert your grep and ping stuff here
fi

<--end edit-->

on first read, i thought your problem sounded ideal for a wrapper script, so i was going to suggest this:

$ cat wrapper.sh
#!/usr/bin/bash

userinput=$1

if [[ $# != 1 ]]   # checks that number of inputs is exactly one
 then
  echo "Too many inputs."
  exit 2
elif [[ $userinput -lt 0 || $userinput -gt 9999 ]]   # checks that the input is within the desired range
 then
  echo "Input outside acceptable range."
  exit 3
fi

output=`d "$userinput"`

ping_address=`grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' <("$output")`

ping "$ping_address"

then call the script with like this:

$ wrapper.sh 1243
like image 28
nullrevolution Avatar answered Nov 21 '25 21:11

nullrevolution



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!