Bash script: always show menu after loop execution
Make it beautiful and userfriendly ;-)
#!/bin/bash
while :
do
clear
cat<<EOF
==============================
Menusystem experiment
------------------------------
Please enter your choice:
Option (1)
Option (2)
Option (3)
(Q)uit
------------------------------
EOF
read -n1 -s
case "$REPLY" in
"1") echo "you chose choice 1" ;;
"2") echo "you chose choice 2" ;;
"3") echo "you chose choice 3" ;;
"Q") exit ;;
"q") echo "case sensitive!!" ;;
* ) echo "invalid option" ;;
esac
sleep 1
done
Replace the echos in this example with function calls or calls to other scripts.
Bash Menu: Return to menu after selection made and executed?
I think, you need something like a loop. Here is a small skelleton for executing a selected line from file:
#!/bin/bash
dumpfile="bla.txt"
echo "ls
echo 'hello'" > ${dumpfile}
function do_action {
line="$( sed -n "${1},1p" "$dumpfile" )"
(
eval "${line}"
)
}
cat -n $dumpfile
nr=$( cat "${dumpfile}" | wc -l )
PS3="select line nr or nr for QUIT: "
select ACTION in $( seq "$nr" ) QUIT
do
case $ACTION in
QUIT) echo "exit" ; break ;; #EXIT
*) do_action "$ACTION" ;;
esac
done
But be aware of the following:
- Using eval might be not allways be a good idea (escaping is hard). Sometimes $line should be sufficient.
- Using a subshell prevents changing variables by executing a line of the file. It also does prevent exiting the script from lines that do normally exits a shell.
how to create a while do done script that has an exit and continue option?
I think this is what you're after.
#!/usr/bin/env bash
RED='\033[0;31m'
NC='\033[0m'
showmenu() {
echo "Type one of the following:"
echo " 1 - whoami"
echo " 2 - df"
echo " 3 - date"
echo " 4 - cal"
}
# Your loop starts here.
while true; do
showmenu # This calls the function above.
read -p "Enter selection: " option
case "$option" in
1) whoami ;;
2) df ;;
3) date ;;
4) cal ;;
*)
echo "${RED}Invalid selection. Exiting.${NC}"
break # Quit the loop, resuming execution after "done"
;;
esac
read -p "Enter another command (y/n)?" cont
case "$cont" in
N*|n*) break ;; # Quit the loop, resuming execution after "done"
*) continue ;; # Restart the loop. Not strictly necessary here,
# since there's nothing left to skip before "done".
esac
done
echo "I quit."
Most of this script does not require bash, by the way; you could run it with /bin/sh
on most systems.
Menu based selection in Shell scripting
This is more of a code review.
- for menus, use
select
- use functions to encapsulate functionality
- paste your code into http://www.shellcheck.net
#!/bin/bash
main() {
cd /
PS3="Enter a choice: "
select ch in "Basic Details" "CPU Information" "Network Information" All Cancel
do
case $ch in
"Basic Details")
basicDetails
;;
"CPU Information")
cpuInfo
;;
"Network Information")
memUsage # you need to fix the menu text
;;
All)
basicDetails
cpuInfo
memUsage
;;
Cancel)
break
;;
esac
done
}
basicDetails() {
echo ">>>>> Server Name, Date, UPtime <<<<<"
echo "====================================="
echo "Date :- $(date)"
echo " "
echo "Host Name :- $(hostname)"
echo " "
echo " OS Version"
oslevel -g
echo " "
echo " UPTIME :- "
uptime
echo " "
echo " "
}
cpuInfo() {
echo ">>>>> CPU and Memory Info. <<<<<"
echo "====================================="
echo " "
echo
echo " CPU :- $(lsdev | grep -c Processor)"
echo " "
echo " Memory :- $(lsattr -El mem0 | tail -1)"
echo " "
echo " "
echo "====================================="
echo ">>>>> Important Kernel Params. <<<<<"
echo "====================================="
echo " "
echo "****************************************"
echo " "
lsattr -El aio0
}
memUsage() {
echo ">>>>> Memory Usage Information <<<<<"
um=$(svmon -G | head -2|tail -1| awk '{print $3}')
um=$(( um / 256 ))
tm=$(lsattr -El sys0 -a realmem | awk '{print $2}')
tm=$(( tm / 1024 ))
fm=$(( tm - um ))
ump=$(( um * 100 / tm ))
echo " "
echo "Memory Used :- $ump%"
echo " "
echo "----------------------"
echo "Memory Information"
echo
echo "total memory = $tm MB"
echo "free memory = $fm MB"
echo "used memory = $um MB"
echo "-----------------------"
echo
echo " "
echo " "
}
main "$@"
Bash submenus (select opt in)
When you break
from the inner select
, you re-enter the top (main menu) select
- as you have discovered, the menu isn't displayed because you don't re-execute the commands at the beginning of the function. Instead, you can break out of the inner and outer selects at once, and have the main menu in a loop so that it gets called again, ie:
1 ) loadkeys be-latin1; echo "AZERTY Keyboard configured"; break 2;;
break 2
will break out of a select nested inside another, break 3
will break out of an additional level of nesting, etc. Then instead of just calling main_menu
at the bottom, do something like:
while :; do main_menu; done
This is an infinite loop which will call main_menu
whenever you break out of the main menu select
command. You may not want it to be infinite, you can always test against a variable or something there.
from the shellscript one option has been chosen OR none of them
thank you SamuelKirschner -
I did to add [[ -n $ALL_OPTS ]] && then it works ! I am happy now.
#!/bin/bash
OPTION1=""
OPTION2=""
OPTION3=""
while (( "$#" )); do
if [ "$1" == "-1" ]; then
OPTION1=1
elif [ "$1" == "-2" ]; then
OPTION2=1
elif [ "$1" == "-3" ]; then
OPTION3=1
fi
shift
done
ALL_OPTS="$OPTION1$OPTION2$OPTION3";
echo $ALL_OPTS
if [[ -n $ALL_OPTS ]] && [[ $ALL_OPTS -ge 2 ]];then
echo 'Please provide a maximum of one of the options [-1|-2|-3]' 1>&2
exit 1
fi
How to implement a regex in a if loop bash script?
Use grep -q
(or egrep -q
for extended version).
# ↓ your string ↓ the pattern
if printf %s "my_string" | grep -q '.*stri.*'
then
echo foo
else
echo bar
fi
Your while
loop condition will look like this:
while printf %s $answer | grep -q '^y$|Y$|Yes$|YES$|yes$|n$|N$|no$|No$|NO$|q$|Q$|Quit$|quit$'
do
: your loop contents here
done
In your conditions, you do not need to use regular expressions at all. Bash has neat syntax construct called case
(similar to C switch
):
read -p "${BASIC}Do you want to install $1 ? (y|n|q)${RESET}" answer
case "$answer" in
[yY])
echo -ne "${OK}Installation of $1 ${RESET}"
# […]
echo -e "\\r${CHECK_MARK}${OK} $1 has been installed or is already installed. ${RESET}"
;;
[nN])
: do nothing
;;
[qQ])
exit 0
esac
Case uses simple patterns. y
means “exactly y
”, you can use [yY]
to provide multiple character variants. Separate multiple patterns by |
for “or”. Asterisk (*
) means “zero or more characters”, question mark (?
) is one character.
Note also that I used read -p PROMPT VAR
to read a text into a variable while displaying a prompt. See read
help for more information, it provides quite a lot of features for reading text in such scripts.
Related Topics
Configure Options for Building Mingw-64 on Linux-64 for Linux-64 (Ultimately Targetting Windows-64)
Switching Users Using Winscp Between Different Accounts
What Does Version Info in Ldd -V Mean
What's the Difference Between 'Push' and 'Pushq' in At&T Assembly
How to Create a File with Any Given Size in Linux
How to Set Runpath of a Binary
Does Linux Support Memory Isolation for Processes
If Adding a Command That Repeats Every 10 Minutes to Crontab, When Does the First Job Run
Where Did Wireshark/Tcpdump/Libpcap Intercept Packet Inside Linux Kernel
Bash Script Variable Scope Issue
Sudoers Nopasswd: Sudo: No Tty Present and No Askpass Program Specified
Catching a Direct Redirect to /Dev/Tty
How to Replace a Multi Line String in a Bunch Files
Haskell Ghc Compiling/Linking Error, Not Creating Executable. (Linux)
How to Get Only Filenames Without Path by Using Grep
Arial Font Required in PDF (Birt PDF Renderer, Linux)
How Many Instructions Does Linux Kernel Need in Order to Handle an Interrupt on an Arm Cortex A9
Combine Results of Column One Then Sum Column 2 to List Total for Each Entry in Column One