Reputation: 1332
So I am trying to make a little custom management script for my server, but I am running into a problem for creating my menu script with the right results.
I got the following script
function config
{
list=''
declare -a programs=("docker" "IdontExist" "pushover" "IdontexistEither")
for program in "${programs[@]}"
do
#Check if command exists on the server
if hash $program 2>/dev/null; then
list="${list} \"${program}\""
fi
done
title="Config manager"
prompt="Pick an option:"
options=(${list})
echo "$title"
PS3="$prompt "
select opt in "${options[@]}" "Quit"; do
case "$REPLY" in
#Dont know how to create this section in a script
1 ) echo "Update Docker"; break;;
3 ) echo "Update IdontExist"; break;;
2 ) echo "Update mytest"; break;;
4 ) echo "Update IdontExistEither"; break;;
$(( ${#options[@]}+1 )) ) echo "Goodbye!"; break;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
}
My list variable will look as follow
list: "docker" "pushover"
So my options in the script above will not work accordingly. How can I create the options, depending on the list variable?
And I also want to call in certain functions depending on the selected option, for example if somebody choose "docker" I want to call a function named: _docker_config and when its "pushover" I will call a function named _pushover_config How would I also achieve that in the script?
Upvotes: 0
Views: 1684
Reputation: 44444
The problem is that you are testing $REPLY
instead of $opt
:
select opt in "${options[@]}" "Quit"
do
if [[ -z $opt ]]; then
echo "Didn't understand \"$REPLY\" "
REPLY=
else
case "$opt" in
docker)
echo "Update Docker"
break;;
IdontExist)
echo "Update IdontExist"
break;;
pushover)
echo "Update mytest"
break;;
IdontexistEither)
echo "Update IdontExistEither"
break;;
Quit)
echo "Goodbye!"
break;;
*)
echo "Invalid option <$opt>. Try another one."
;;
esac
fi
done
If you use $opt
then you don't need to match the menu numbers (which in your case are variable) with the actual entries (program names) - select
does that for you. The only time you need $REPLY
is when it is invalid (setting REPLY
to an empty string redisplays the menu on the next iteration).
Not all of the choices in the case
statement will be valid for every run, but that's OK because $opt
will only get populated by the valid ones, and the others will not be visible to the user.
You don't need the continue
, it does that for you by being in a loop.
Edit:
Here is an alternative using an Associative Array instead of a case statement. It enables the menu and the tests to be dynamic. In the case shown only two of the options have function, that does not have to be the case, it can be any number (with reason).
_docker_config()
{
echo "Welcome to docker"
}
_pushover_config()
{
echo "Welcome to pushover"
}
# This declares and associative array with the keys being the menu items
# and the values being the functions to be executed.
# This will have to include all possible programs
declare -A functab=(["Docker"]=_docker_config
["Pushover"]=_pushover_config)
title="Config manager"
prompt="Pick an option:"
# The options are hard-coded here, of course you will dynamically generate it
# I omitted that for testing purposes
declare -a options=("Docker" "IdontExist" "Pushover" "IdontexistEither")
echo "$title"
PS3="$prompt "
select opt in "${options[@]}" "Quit"
do
if [[ $opt == "Quit" ]]; then
echo "Goodbye!"
break
fi
if [[ -z $opt ]]; then
echo "Didn't understand \"$REPLY\" " >&2
REPLY=
else
# Here we check that the option is in the associative array
if [[ -z "${functab[$opt]}" ]]
then
echo "Invalid option. Try another one." >&2
else
# Here we execute the function
eval ${functab[$opt]} # See note below
fi
fi
done
The eval is used with caution. Generally this is a command to avoid because it can be a security issue, however we are checking for valid entries so in this case it is justified. Just don't over-use it.
Upvotes: 2