I want to create a script where I have pre-defined option values.
opt1 opt2 opt3
I will start a script and it will ask me to choose from opt1 - opt3.
Once I pick e.g. opt2, that opt2 will then be passed as a variable.
How can I please achieve it?
You can use the "case" command to check if the user value is on a list of expected values:
#!/bin/bash
selected_option=""
echo " *** MENU ***"
echo "1) Opt1"
echo "2) Opt2"
echo "3) Opt3"
echo -n " Please, enter your option: "
read user_answer
case $user_answer in
1|2|3) selected_option="$user_answer"
;;
*) echo "Invalid Option!"
esac
##### Show the result only if the user selected an valid option #####
if [[ ! -z "${selected_option}" ]]; then
echo "Selected Option: [${selected_option}]"
fi
The '|' can be used to separate the valid options, and it will act as an "or" operator.
The '*' section will be executed if the previous condition is not satisfied, which means a "default" behavior, at this case it will display "Invalid Option" message.
Finally, the last if checks if the variable "${selected_option}" is empty, if not it is printed, but you can do whatever you want with that.
#!/bin/sh
echo "choose an option [ 1 opt1 | 2 opt2 | 3 opt3 ]"
read input
if [ $input == 1 ]
then
output="option 1 was chosen"
elif [ $input == 2 ]
then
output="option 2 was chosen"
elif [ $input == 3 ]
then
output="option 3 was chosen"
else
output="invalid input"
fi
echo "$output"
Related
I'm trying to implement a prev option in my bash script to go back to the previous "menu", as well as a way for the script to ask for user input again if no variable is set for $name.
Heres my bash script:
#!/bin/bash
#Menu() {
for (( ; ; ))
do
beginORload=
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
read -p "?" beginORload
#}
#Begin() {
if [ "$beginORload" -eq "1" ]
then
clear
for (( ; ; ))
do
echo "Beginning. What is your name?"
read -p "?" name
#If "prev" specified, go back to #Menu()
if [ "$name" -eq "prev" ]
then
Menu
fi
#If nothing specified, return to name input
if [ -z ${name+x} ]
then
Begin
else
break
fi
echo "Hi $name !"
done
fi
done
In batch, I could simply do:
:menu
echo Choose option:
echo 1 - Begin
echo 2 - Load
[...]
:begin
[...]
if "%name%==prev" goto menu
if "%name%==" goto begin
the issue is I keep running into errors all over the place, and I can't figure out what to type to get it to work
im running Yosemite btw. Thankyou
Something like this is close to what you expect:
while [[ $answer -ne '3' ]];do
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
echo "3 - Exit"
read -p "Enter Answer [1-2-3]:" answer
case "$answer" in
1) while [[ "$nm" == '' ]];do read -p "What is your Name:" nm;done # Keep asking for a name if the name is empty == ''
if [[ $nm == "prev" ]];then nm=""; else echo "Hello $nm" && break; fi # break command breaks the while wrapper loop
;;
2) echo 'Load' ;;
3) echo 'exiting...' ;; # Number 3 causes while to quit.
*) echo "invalid selection - try again";; # Selection out of 1-2-3 , menu reloaded
esac # case closing
done # while closing
echo "Bye Bye!"
As a general idea you can wrap up your case selection in a while loop which will break under certain circumstances (i.e If Option 3 is selected or if a valid name is given (not blank - not prev)
PS1: In bash you compare integers with -eq , -ne, etc but you compare strings with == or !=
PS2: Check the above code online here
This question already has an answer here:
Until user input matches variable do
(1 answer)
Closed 8 years ago.
I am trying to validate the value of an input variable, and prompt the user for valid value, until I get a valid input ('1' or '2'). I've tried:
while option not in 1 2
do :
read -p "Please choose an option" option
done
How this can be done in bash?
The classical way is:
while ! { test "$option" = 1 || test "$option" = 2; }; do ...
but a cleaner way is to use a case statement:
while :; do
case "$option" in
1|2) break ;;
*) ... ;;
esac
done
Use the select builtin:
$ cat select.sh
#!/bin/bash
options=("Option 1" "Option 2")
echo "Please choose an option:"
select option in "${options[#]}"; do
[ -n "${option}" ] && break
done
echo "You picked: ${option}"
$ ./select.sh
Please choose an option:
1) Option 1
2) Option 2
#? 3
#? xyz
#? 2
You picked: Option 2
In bash, you can use pattern matching to test $option:
while [[ $option != [12] ]]; do
read -p "Please choose an option: " option
done
I'd do something like that:
#!/bin/bash
while : ; do
echo "Please choose an option"
read val
[[ $val != 1 && $val != 2 ]] || break
done
Or if you plan to evaluate more options, use case:
#!/bin/bash
while true; do
read -p "Please choose an option" option
case "$option" in
[12]) break
;;
*) echo "whatever"
esac
done
You can use this while condition using {...} list construct and shell globbing:
option=0
while [[ $(echo {1,2}) != *"$option"* ]]; do
read -p "Please choose an option: " option
done
I think this is the most common way
while [[ "$option" -ne 1 ]] || [[ "$option" -ne 2 ]]; do
read -p "Please choose an option" option
done
My script
#!/bin/bash
while :
do
echo "[*] 1 - Create a gnome-terminal"
echo "[*] 2 - Display Ifconfig"
echo -n "Pick an Option > "
read Input
if [ "$Input" = "1" ]; then
gnome-terminal
sleep 3
echo "[*] 1 - Create a gnome-terminal"
echo "[*] 2 - Display Ifconfig"
echo -n "Pick an Option > "
read Input
fi
if [ "$Input" = "2" ]; then
clear
ifconfig
echo "[*] 1 - Create a gnome-terminal"
echo "[*] 2 - Display Ifconfig"
echo -n "Pick an Option > "
read Input
fi
done
Doesn't reuse the Input variable, say if you want to run the ifconfig option multiple times in a row. It rechecks the first variable string to see if it matches "1", and when it doesn't it echoes back the list of options. Any ideas on how to make any input variable accessible regardless of when it is used?
The problem is that you're writing out the menu twice on each iteration. Stop doing that:
#!/bin/bash
while :
do
echo "[*] 1 - Create a gnome-terminal"
echo "[*] 2 - Display Ifconfig"
echo -n "Pick an Option > "
read Input
if [ "$Input" = "1" ]; then
gnome-terminal
sleep 3
fi
if [ "$Input" = "2" ]; then
clear
ifconfig
fi
done
Use select instead of rolling your own menu:
choices=(
"Create a gnome-terminal"
"Display Ifconfig"
)
PS3="Pick an Option > "
select action in "${choices[#]}"; do
case $action in
"${choices[0]}") gnome-terminal; sleep 3;;
"${choices[1]}") clear; ifconfig;;
*) echo invalid selection ;;
esac
done
select gives you an infinite loop by default. If you want to break out of it, put a break statement into the case branch.
I'm creating a shell script that takes in user input and text's people using the mail function. I am looking to make it more advanced. Right now it just text's one person at a time, I want it to have the ability to text multiple people or even everyone with a user input of 'All'.
#!/bin/sh
# Prefix the numbers with something
number_Joe=8881235555
number_Bob=8881235556
echo "Who do you want to text?:(i.e. Joe, Bob, etc)"
read name
echo "What do you want to say?:"
read quote
# Remove any dangerous characters that the user enters
sanitized=$(printf "%s" "$name" | tr -cd 'a-zA-Z')
#Look up by evaluating e.g. "number=$number_Joe"
eval "number=\$number_$sanitized"
if [ "$number" ]
then
echo "texting $name ($number) with $quote"
printf "%s\n" "$quote" | mailx -s "Text Message via email" "$number#txt.att.net"
else
echo "Unknown user"
exit 1
fi
Also, is there a cleaner method of bringing in a external txt file that houses the numbers instead of the script?
(note: we still have bash <4, thus why I'm not using a associative array)
Here's a rewrite.
Should work fine in bash3.
#!/bin/bash
# Prefix the numbers with something
names=()
names+=(Joe); numberJoe=8881235555
names+=(Bob); numberBob=8881235556
domain=txt.att.example.com
usage () {
echo "usage: $(basename $0) names message ..."
echo "where: names is a comma-separated list of names (no spaces)"
echo
echo "example: $(basename $0) Jim,Fred hello lads, this is my message"
}
while getopts ":hl" opt; do
case $opt in
h) usage; exit ;;
l) IFS=,; echo "known names: ${names[#]}"; exit ;;
esac
done
shift $((OPTIND - 1))
if (( $# < 2 )); then
usage
exit
fi
IFS=, read -ra usernamelist <<<"$1"
shift
message="$*"
# validate names
namelist=()
for name in "${usernamelist[#]}"; do
if [[ " ${names[#]} " == *" $name "* ]]; then
namelist+=("$name")
else
echo "unknown name: $name" >&2
fi
done
if (( ${#namelist[#]} == 0 )); then
echo "no valid names given" >&2
exit 1
fi
# generate the recipient list
echo "texting '$message' to:"
recipients=()
for name in "${namelist[#]}"; do
numvar="number$name"
echo " $name -> ${!numvar}"
recipients+=( "${!numvar}#$domain" )
done
# send it
printf "%s\n" "$message" | mailx -s "Text Message via email" "$(IFS=,; echo "${recipients[*]}")"
I have these two scripts, configScript.shand genScript.sh. The first one works just the way I want it to work. It adds the correct values into options.sh and echo the right message. However, I want genScript.sh to accept the current argument in options.sh and output the correct echo. As it is now when I run genScript.sh it returns null and I can't figure out why.
#!/bin/bash -x
#configScript.sh
func()
{
echo "
Choose
1 - Option 1
2 - Option 2
"
echo -n " Enter selection: "
read select
case $select in
1 )
echo " Option 1 chosen"
. ./genScript.sh one
cat << EOF >options.sh
OPTION=$OPTION
EOF
;;
2 )
echo " Option 2 chosen"
. ./genScript.sh two
cat << EOF >options.sh
OPTION=$OPTION
EOF
;;
esac
}
func
#!/bin/bash -x
#genScript.sh
. options.sh
OPTION=$1
func2()
{
if [ "$OPTION" == one ] ; then
echo "Option one"
elif [ "$OPTION" == two ] ; then
echo "Option two"
else
echo "null"
fi
}
func2
I managed to get genScript.sh to work the way I want by removing OPTION=$1. When I do that genScript.sh will accept the value inside options.sh and will output the right echo . BUT when I remove OPTION=$1 configScript.sh stops working as it should, it doesn't update options.sh with a new value anymore.
The problem is with the way you want genScript to be called. I think you want to run genScript with command line argument and as-well as with sourcing from options.sh.
Below changes to genScript.sh would serve the purpose. It gives preference to command line when both command line and options.sh have values.
#!/bin/bash -x
#genScript.sh
OPTION=""
. options.sh
[ "$1" ] && OPTION=$1
func2()
{
if [ "$OPTION" == one ] ; then
echo "Option one"
elif [ "$OPTION" == two ] ; then
echo "Option two"
else
echo "null"
fi
}
func2
Just put quotes around "one" and "two" in the second script and in the first script where it generates options.sh and added default value $OPTION to the OPTION var in the second script so now it works.
#!/bin/bash -x
#configScript.sh
func()
{
echo "
Choose
1 - Option 1
2 - Option 2
"
echo -n " Enter selection: "
read select
case $select in
1 )
echo " Option 1 chosen"
. ./genScript.sh one
cat << EOF >options.sh
OPTION="$OPTION"
EOF
;;
2 )
echo " Option 2 chosen"
. ./genScript.sh two
cat << EOF >options.sh
OPTION="$OPTION"
EOF
;;
esac
}
func
#!/bin/bash -x
#genScript.sh
. options.sh
OPTION=${1-$OPTION}
func2()
{
if [ "$OPTION" == "one" ] ; then
echo "Option one"
elif [ "$OPTION" == "two" ] ; then
echo "Option two"
else
echo "null"
fi
}
func2
That is one of the most irritating problems. I don't know if you are using editor with syntax highlighting but you better be so you run easily over this type of issues.