Bash Script: Always Show Menu After Loop Execution

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



Leave a reply



Submit