2

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

tshepang
  • 12,111
  • 21
  • 91
  • 136
Zippyduda
  • 107
  • 2
  • 7
  • 19

4 Answers4

5

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
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
2

If you just want a number between two values, you can test their values:

 read x
 while [[ $x -lt 0 || $x -gt 9999 ]]; do
    echo "bad value for x"
    read x
 done
 echo "x=$x"
eduffy
  • 39,140
  • 13
  • 95
  • 92
2

<--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
nullrevolution
  • 3,937
  • 1
  • 18
  • 20
0

The read command doesn't prompt itself. Use a normal echo before to actually display a prompt. Use echo -n to not add a newline.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Searching around for "bash prompt for input" just comes back with example of using read like so: read -p "Enter value" variable case "variable" in...how do I prompt via echo or reference read from echo. e.g. http://stackoverflow.com/questions/1885525/how-do-i-prompt-a-user-for-confirmation-in-bash-script – Zippyduda Jan 17 '13 at 15:22
  • @Zippyduda The `-p` option is an extension that doesn't exist in the [standard](http://pubs.opengroup.org/onlinepubs/009695399/utilities/read.html). – Some programmer dude Jan 17 '13 at 15:32
  • Hm, fair enough. Why is it used in that link I posted? – Zippyduda Jan 17 '13 at 15:38
  • @Zippyduda Ah, I found it now in the [Bash manual](http://linux.die.net/man/1/bash). It's a Bash-specific extension. Have you tried it? – Some programmer dude Jan 17 '13 at 15:42