Reputation: 1637
I am trying to create a simple bash script that tells the user to enter a char. The user only has a limited number of possible options to enter. If he enters the correct one out of the options allotted, then that option is then returned back from the function. If not, then the user is asked to enter a correct option.
Here is the script I wrote:
#receive from the user an input and verify that it is a valid option. If not, try again.
#input1: The number of valid options
#input2: array of valid inputs (can be single characters or strings).
# EXAMPLE:
# ARRAY=("a" "b")
# ReceiveValidInput 2 "${ARRAY[@]}" # there are TWO valid options. Valid options are ${ARR[0]}="a", ${ARR[1]}="b"
function ReceiveValidInput()
{
echo "testing"
InputNum=$1 #get the first input1
shift # Shift all arguments to the left (original $1 gets lost)
ARRin=("$@") #get the second input2 in the form of an array
ProperInputFlag="false"
while [[ "$ProperInputFlag" == "false" ]]; do
echo "enter input and then press enter"
read UserInput
index=0
while [[ $index < $InputNum ]]; do
if [[ "${ARRin[index]}" == "$UserInput" ]]; then
echo $UserInput #we do echo because this is how it is returned back (see https://stackoverflow.com/a/17336953/4441211)
ProperInputFlag="true" #this will cause the while loop to break and exit the function
fi
index=$((index+1))
done
if [[ "$ProperInputFlag" == "false" ]]; then
echo "Invalid input. Please enter one of these options:"
index=0
while [[ $index < $InputNum ]]; do
echo "Option1 $((index+1)): " ${ARRin[index]}
index=$((index+1))
done
fi
done
}
I use the function this way:
ARRAY=("a" "b")
testing=$(ReceiveValidInput 2 "${ARRAY[@]}")
echo "Received: "$testing
read -p "press enter to exit"
exit 1
And it does not work. This syntax testing=$(ReceiveValidInput 2 "${ARRAY[@]}")
simply causes the script to get stuck and nothing happens.
However, if I run ReceiveValidInput 2 "${ARRAY[@]}"
then the function gets called and everything work except I don't get to capture the "return" value.
Any idea how to write the syntax correctly for calling the function so that I can obtain the "return" value which is technically echoed back?
Upvotes: 0
Views: 154
Reputation: 34054
@GordonDavisson has addressed the issue of why the current function call gets stuck and appears to do nothing.
So, how to make the function call (without getting 'stuck') and provide the calling process with the 'return value'?
Assuming the value to be returned by the function is the value in the UserInput
variable (ie, echo $UserInput
), you can use the fact that a function call does not invoke a subprocess which in turn means that variable assignments made in the function are available to the parent/calling process.
NOTE: wrapping a function call in $(..)
will invoke a subprocess which in turn means the parent/calling process won't have access to values assigned in the function call
Here's an example
$ myfunc () {
x=5
}
$ x=6
$ myfunc # call the function; no subprocess involved
$ echo "${x}"
5 # value set by the function is available to the parent
$ x=9
$ y=$(myfunc) # call the function in a subprocess
$ echo "${x}"
9 # x=5, set by the function, is not available to the parent
Pulling this info into the current set of code:
$ function ReceiveValidInput() { .... } # no changes to the function definition
$ ARRAY=("a" "b") # same array assignment
$ ReceiveValidInput 2 "${ARRAY[@]}" # call the function
$ echo "Received: ${UserInput}" # reference 'UserInput' value that was set within the function call
If there's a need to let the parent/calling process know there was a problem then the function can return
an integer to the parent/calling process.
Calling the myfunc()
function (as defined above):
$ myfunc
$ rc=$?
$ echo $rc
0 # default return code when the last command
# executed by the function is successful
We can have the function pass a non-zero return code ($?
) via the return
command, eg:
$ myfunc2 () {
x=9
return 3 # simple example that will always return '3'; this
# can be made dynamic with 'return ${SomeVariable}'
}
$ myfunc2
$ rc=$?
$ echo $rc
3
Upvotes: 2
Reputation: 530950
Veering way off topic to point out that you are re-inventing the wheel to some extent, bash
has a built-in command for getting interactive input from a set of fixed choices:
select testing in a b; do [[ $testing ]] && break; done
This will display a menu, letting the user choose a value by number, and repeating until a valid choice is made.
Upvotes: 2