bash case statement with unmatched patterns - bash

Ok, so i have tried searching for this on google and i cant seem to find an answer. What i'm trying to do is create a case statement in bash but if the user enters a different number than listed it just exits the script. How do i make it give an error and then ask for the user to select one of the options?
for example, my case statement
case $ans in
1) echo "Running Project 1..."
sleep 2
./project1.sh
;;
2) echo "Running Project 2..."
sleep 2
./project2.sh
;;
Qq) echo "Exiting"
exit
;;
esac
so any options other than 1, 2, Qq it will give an error saying invalid selection, try again.

You need a while loop and a boolean variable like that:
flag = true
while [ $flag ]; do
case $ans in
1) echo "Running Project 1..."
sleep 2
./project1.sh
;;
2) echo "Running Project 2..."
sleep 2
./project2.sh
;;
Qq) echo "Exiting"
flag = false
;;
esac
done

Related

Bash menu script with possibility to run with arguments

I have a bash script:
PS3='Please enter your choice: '
options=("1" "2" "3" "4" "Quit")
select opt in "${options[#]}"
do
case $opt in
"1")
echo "Set configuration"
break
;;
"2")
echo "Setting configuration and execution Install"
break
;;
"3")
echo "Setting configuration and execution Unlink"
break
;;
"4")
echo "Running tests"
break
;;
"Quit")
break
;;
*) echo "Selected option '$REPLY' couldn't be find in the list of options";;
esac
done
I have 2 questions:
How can I run this script with predefined option? (For example, I want to execute this script with already selected 1st option)
Is it possible to reuse one option in another option? (For example my 1st option just setting config and my 2nd option also setting the same config and after that execute install, can they be written like if option 2 selected execute 1st option and then 2nd?)
And if something written too badly, I'm open to suggestions =)
How can I run this script with predefined option? (For example, I want
to execute this script with already selected 1st option)
It's a bit ugly with select, move all case logic out from do ... done cycle, make your script take args and rearrange it like this:
#!/bin/bash
PS3='Please enter your choice: '
options=("1" "2" "3" "4" "Quit")
[[ $1 ]] && opt=$1 || select opt in "${options[#]}"; do break; done
case $opt in
"1") echo "Set configuration";;
"2") echo "Setting configuration and execution Install";;
"3") echo "Setting configuration and execution Unlink";;
"4") echo "Running tests";;
"Quit") :;;
*) echo "Selected option '$REPLY' couldn't be find in the list of options";;
esac
Is it possible to reuse one option in another option? (For example my
1st option just setting config and my 2nd option also setting the same
config and after that execute install, can they be written like if
option 2 selected execute 1st option and then 2nd?)
Turn the code in options into functions, this way you could easily reuse it
fun1(){ echo "Set configuration"; }
fun2(){ echo "Execution Install"; }
...
case $opt in
"1") fun1;;
"2") fun1; fun2;;
...
Also there are these operators for case: ;& and ;;&
man bash
...
Using ;& in place of ;; causes execution to continue with the list associated with the next set of patterns.
Using ;;& in place of ;; causes the shell
to test the next pattern list in the statement, if any, and execute any associated list on a successful match.
So if you want to make option 1 also run if option 2 selected this can be done like so:
case $opt in
"2") fun1;&
"1") fun1;;
...
But personally I found this method a bit tricky and hard to read.
If you put the select part in a function
main(){
select opt in "${options[#]}"
do
case $opt in
"1")
set_config # <--- an other funtion for option 1 to reuse it
break
;;
.
.
.
}
# set a default option
def_opt=1
# or use command line argument
def_opt="$1"
you can call main with predefined option '$def_opt' with yes
yes "$def_opt" | main
After digging into this and trying to do my best, I still need a little help to finish my script.
Running script without any parameters are now working perfect.
Passing options in that way (getopts :c:i:u:d:s:h:) leads me to an error message after executing command sh ./script.sh -c => Wrong argument 'c' provided, run sh ./scripts/collection.sh -h for help
Passing options in that way (getopts "ciudsh") => working perfect, but still if I use argument that wasn't passed (ex. x) it would lead to error: Wrong argument '' provided, run sh ./scripts/collection.sh -h for help or sometimes even to this Syntax error: "(" unexpected (expecting "fi")
Please see my full script below, unfortunately for security reasons I can't post the content of the functions itself.
I would appreciate any help on fixing style, errors or anything else.
Based on your advice and other answers on stackoverflow I came up to this:
#!/usr/bin/env bash
#Colors
BRed='\033[1;31m'
Green='\033[0;32m'
BCyan='\033[1;36m'
NC='\033[0m'
f1(){
...
}
f2(){
...
}
f3(){
...
}
f4(){
...
}
f5(){
...
}
Help(){
echo -e "${Green}====================================================================================================================${NC}"
echo "You may execute the commands by selecting a number from menu or pass it as argument, see examples below:"
echo ""
echo -e "${Green}sh $0 ${BCyan}-argument${NC} :To execute specific command"
echo -e "${Green}sh $0 ${NC} :To see menu with all available options"
echo ""
echo -e "${BCyan} -c ${NC}..."
echo -e "${BCyan} -i ${NC}..."
echo -e "${BCyan} -u ${NC}..."
echo -e "${BCyan} -d ${NC}..."
echo -e "${BCyan} -s ${NC}..."
echo -e "${BCyan} -h ${NC}..."
echo -e "${Green}====================================================================================================================${NC}"
exit 1;
}
if [ $# -eq 0 ]
then
PS3='Please enter your choice: '
options=("1" "2" "3" "4" "5" "Help" "Quit")
select opt in "${options[#]}"
do
case $opt in
"1")
f1;;
"2")
f1; f2;;
"3")
f1; f2;;
"4")
f3;;
"5")
f4;;
"Help")
Help;;
"Quit")
break;;
*) echo -e "${BRed}Selected option ${BCyan}'$REPLY'${NC} ${BRed}couldn't be find in the list of provided options${NC}"
break;;
esac
done
fi
while getopts :c:i:u:d:s:h: OPTION
do
case $OPTION in
c)
f1;;
i)
f1; f2;;
u)
f1; f3;;
d)
f4;;
s)
f5;;
h)
Help;;
*) echo -e "${BRed}Wrong argument ${BCyan}'$OPTARG'${NC} ${BRed}provided, run${NC} ${BCyan}sh $0 -h${NC} ${BRed}for help${NC}"
esac
done

Trying to execute a function through a users choice with the select command Bash

I am trying to get a function to execute after a user makes a selection from a menu, but I am having trouble figuring out what I am supposed to do to get it to execute. All I am getting is the program performing an echo of the function name.
#!/bin/bash
function task1 {
echo "Hello"
}
function task2 {
echo "how are you"
}
function task3 {
echo "Im good thanks for asking"
}
PS3='Please select one of the options: '
select _ in \
'Exit program' \
'task1' \
'task2' \
'task3' \
do
case $REPLY in
1) echo exit ;;
2) echo task1 ;;
3) echo task2 ;;
4) echo task3 ;;
*) echo 'Invalid selection, please try again.' ;;
esac
done
Output
1) Exit program
2) Find the even multiples of any number.
3) Find the terms of any linear sequence given the rule Un=an+b.
4) Find the numbers that can be expressed as the product of two nonnegative integers in succession and print them in increasing order.
Please select one of the options: 1
exit
Please select one of the options: 2
task1
Please select one of the options: 3
task2
Please select one of the options: 4
task3
Please select one of the options: .
Invalid selection, please try again.
Please select one of the options:
Your case block has a bunch of echo calls. Get rid of those.
Functions mimic regular commands. To call them you just write the function name. Don't put echo as that's going to just print a message.
case $REPLY in
1) exit ;;
2) task1 ;;
3) task2 ;;
4) task3 ;;
*) echo 'Invalid selection, please try again.' ;;
esac

Bash Case/Switch Formatting

I'm trying to write a case/switch statement in my bash script as follows:
case "$REPLY" in
E*|e*) $EDITOR "$COMMIT_MSG_FILE" < $TTY; continue ;;
Y*|y*) exit 0 ;;
N*|n*) exit 1 ;;
*) SKIP_DISPLAY_WARNINGS=1; create_prompt; continue ;;
esac
However, I keep getting
syntax error near unexpected token ';;'
E*|e*) $EDITOR "$COMMIT_MSG_FILE" < $TTY; continue ;;'
From reading around, I know that ;; is the equivalent of a break statement in a traditional switch statement, but I'm not sure why I'm getting a syntax error here. All of the functions and variables are defined above, so I can't see that being an issue. Any advice?
EDIT: Entirety of the loop:
while true; do
read_commit_message
check_commit_valid
# if there are no warnings, then the commit is good and we can exit!
test ${#WARNINGS[#]} -eq 0 && exit 0;
# if we're still here, there are warnings we need to display
show_warnings
# if non-interactive don't prompt and exit with an error
# need interactivity for the prompt to show and get response
if [ ! -t 1 ] && [ -z ${FAKE_TTY+x} ]; then
exit 1
fi
# show message asking for proceed, etc
echo -en "${BLUE}Proceed with commit? [e/y/n/?] ${NO_COLOR}"
# read the response
read REPLY < "$TTY"
# Check if the reply is valid
case "$REPLY" in
E*|e*) $EDITOR "$COMMIT_MSG_FILE" < $TTY; continue ;;
Y*|y*) exit 0 ;;
N*|n*) exit 1 ;;
*) SKIP_DISPLAY_WARNINGS=1; create_prompt; continue ;;
esac
done

BASH : got to the upper imbricated case

It is my first question, so I hope that I'm clear enough
I have the following problem with a case inside a case.
the first one is a menu which trigger a function. inside the function there a an other case. In case user select NO, he should come back to the first case.
I have not found how to do that beside of launching the first script ( containing the first case:
menu.sh:
source ./functions.sh
#read answer
while read answer;do
case $answer in
1)
function1
;;
2)
function2
;;
3)
# the same, without function
read -p "do you want to continue [y/n] ?" choice
case $choice in
y|Y)
# DO SOME STUFF
menu.sh
;;
n|N )
./menu.sh
;;
*)
echo "invalid input"
./menu.sh
;;
esac
4)
function4
;;
5)
quit
;;
esac
done
functions.sh:
function1() {
read -p "do you want to continue [y/n] ?" choice
case $choice in
y|Y)
# DO SOME STUFF and go back to menu
echo "hello"
menu.sh
;;
n|N )
./menu.sh
;;
*)
echo "invalid input"
./menu.sh
;;
esac
}
so as you can see, when the function is launched, it launched the second case where the user is asked if he wants to continue. If he choose no, he can go back the menu. But with the way i m doing, i m spawning a menu.sh inside the case.
What is the better solution?
Thank you in advance for your help
As your code layed out, you don't need to run anything to go back to the menu. Just delete the lines in which you are spawning the menu.sh.
An example function1 would look like:
function1() {
read -p "do you want to continue [y/n] ?" choice
case $choice in
y|Y)
# DO SOME STUFF and go back to menu
echo "hello"
;;
n|N )
;;
*)
echo "invalid input"
;;
esac
}
And change
while read answer;do
To
while read -p "Enter a number: " answer;do
It will make it easier to understand how things are working.

How do I change a user input variable?

Here is what I have
echo "Please select an Environment "
PS3="Please enter 1-6: "
select env in dev qa test staging production quit
do
case $env in
dev|qa|test|staging|production|quit)
break
;;
*)
break
;;
esac
done
echo $env
What I want is when someone selects and env variable I want to translate it.
For example Production would translate to $env=portal
Script:
#!/usr/bin/env bash
declare -ar OPTIONS=('dev' 'qa' 'test' 'quit')
PS3="Please enter 1-${#OPTIONS[#]}: "
select OPTION in "${OPTIONS[#]}"
do
case ${OPTION} in
'dev')
env='Development environment'
break
;;
'qa')
env='Quality Assurance environment'
break
;;
'test')
env='Test environment'
break
;;
'quit')
echo 'See ya' && exit 0
;;
*) echo 'invalid option';;
esac
done
echo "env = ${env}"
exit 0
Example of usage:
$ ./so_q28397293.sh
1) dev
2) qa
3) test
4) quit
Please enter 1-4: 1
env = Development environment
$ ./so_q28397293.sh
1) dev
2) qa
3) test
4) quit
Please enter 1-4: 5
invalid option
Please enter 1-4: 4
See ya
$
Is it what you wanted?
Don't forget that test is reserved word in Bash(that is why I quoted it):
$ bash -c "help test"
test: test [expr]
Evaluate conditional expression.
Exits with a status of 0 (true) or 1 (false) depending on
the evaluation of EXPR. Expressions may be unary or binary. Unary
expressions are often used to examine the status of a file. There
are string operators and numeric comparison operators as well.
...
You can try:
echo "Please select an Environment "
echo -n "Please enter 1-6: "
read ARG
case $ARG in
1) ENV="dev" ;;
2) ENV="qa" ;;
#etc
esac
echo $env

Resources