Bash submenus (select opt in) - linux

I am trying to make a complete BASH menu with submenus via select opt in.
The problem : When I go to a submenu then come back to the initial menu, it do not show options.
----------------------------------------------
Greenwatch's Kiosk debug menu
----------------------------------------------
1) Keyboard Layout, 5) Configure Kiosk's password,
2) Timezone configuration, 6) Set Proxy,
3) -, 7) Remove Proxy
4) Launch Kiosk anyway,
Enter your choice (mainmenu), press 0 to reboot: 1
1) Azerty layout (BE)
2) Querty layout (US)
3) Cancel
Enter your choice (submenu): 1
AZERTY Keyboard configured
Enter your choice (mainmenu), press 0 to reboot:
This is the code(simplified -with only one submenu- )
choose_keyboard() {
show_title "Choose your keyboard layout"
clear;
select opt in "Azerty layout (BE)" "Querty layout (US)" "Cancel"; do
case "$REPLY" in
1 ) loadkeys be-latin1; echo "AZERTY Keyboard configured"; break;;
2 ) loadkeys us; echo "QWERTY Keyboard configured"; break;;
3 ) echo "Canceled"; break;;
777 ) break;;
*) echo "This is not a valid option, retry";;
esac
done
}
main_menu() {
show_title "$title"
select opt in "${options[#]}"; do
case "$REPLY" in
0 ) show_title "See you as late as possible!"; sudo systemctl reboot;;
1 ) choose_keyboard;;
2 ) choose_timezone;;
3 ) lauch_kiosk;;
4 ) choose_password;;
5 ) choose_ipconfig;;
6 ) choose_proxy;;
7 ) choose_testlab;;
777 ) break;;
*) echo "This is not a valid option, retry";;
esac
done
}
main_menu
How could I force select to display the menu?
NOTE: If I call main_menu into the choose_keyboard function, I will certainly obtain a stackoverflow error!

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.

Related

How to close zenity window by press on Cancel button?

I have until loop and I can't get it how to break the loop when I click Cancel button? My until loop looks like this:
until [[ "$VAR" == "End" && **<second cond. for cancel>** ]]; do
...
The problem is if I want to close the window I have to click on the red cross. If I want to do this with the "cancel" button, the window does not respond to it.
Tried to find the return value information after clicking cancel, and do an expression for that.
I wonder what the condition should be for it to work properly instead <second cond. for cancel>
SOLUTION: as someone said, <secound cond. for cancel> should be $? == 1. It works fine now.
Zenity exits with an exitcode of 1 if you press the cancel button (or close the dialog window, or press <Escape>). You could write something like this:
#!/bin/bash
rc=0
until [[ $VAR == "End" || $rc == 1 ]]; do
VAR=$(
zenity --entry --text "Choose an action"
)
rc=$?
done
This loop will exit if you enter End in the text field, or if you press the Cancel button.

Breaking out of nested function loops in Bash

I am using a nested function to partition and making the filesystem for drives attached to a new Linux box.
I am having a strange issue trying to break out of all loops.
I am keeping track of the nested loop index and using "break n".
When the user replies "n" to the question "Do you have any additional drives to partition?" i expect to break out of all nested loops and continue with the script, but what happens is that the question gets asked again.
Can you help me figure this out?
INIT_STARTED=0
chooseDisks()
{
INIT_STARTED=$((INIT_STARTED+1))
# Choosing which drive to work on
read -p "Please type the name of the disk you want to partition: " DISK
while true; do
read -p "Are you sure you want to continue ? y (partition)/n (choose another drive) /x (continue) " ynx
case $ynx in
[Yy]* )
containsElement "$DISK"
if [ $? == 1 ]; then
initializeDisk $DISK
# remove element from found disk to prevent trying to partition it again.
delete=($DISK)
FOUNDDISKS=( "${FOUNDDISKS[#]/$delete}" )
else
echo "${red}$DISK is not a valid choice, please select a valid disk.${reset}"
chooseDisks
fi
break;;
[Nn]* )
chooseDisks
break $((INIT_STARTED));;
[Xx]* )
return
break;;
* ) echo "Please answer y or n. x to continue the script.";;
esac
done
# Any additional disks to partition?
while true; do
read -p "Do you have any additional drives to partition ? y/n " yn
case $yn in
[Yy]* )
#chooseDisks $FOUNDDISKS
chooseDisks
break $((INIT_STARTED));;
[Nn]* )
return
break $((INIT_STARTED));;
* ) echo "Please answer y or n";;
esac
done
}
I expect this:
break $((INIT_STARTED));;
to end the nth loop and exiting the function.
Don't play with nested logic break, just use some variable like $userStop and instead of while true; do put
userStop = false
while[!${userStop}]
do
#...
# replace break $((INIT_STARTED));; by
# userStop = true
I ended up changing the code to avoid breaking within a loop.
Thanks guys for directing me the right way.
David
i expect to break out of all nested loops and continue with the script
You can run the function in a subshell and use exit.
chooseDisks()
{
if [ "$1" -eq 0 ]; then
echo "The user entered it all!"
exit 0
fi
echo "The user is still entering... $1"
( chooseDisks $(($1 - 1)) )
}
# Imagine the user 5 times enters something
( chooseDisks 5 )
But the best would be to refactor your code to just have a big while true; do loop in the beginning. There is no need to make this function recursive.

How to update variable within case statement based on user input

I have created a bash script which is essentially a wizard with a number of questions, some are multiple choice. When a multiple choice question is presented, I want the user to be able to choose a number, where each number corresponds to a different answer. I want this answer to be the variable which can be later used in the script.
I realize this is what the 'select' function is used for, but I also have a requirement when the user simply hits [ENTER] a default value is assumed. As far as I know, the 'select' function assumes an empty value of "" when the [ENTER] key is pressed (an invalid option) and re-prompts the question.
The code below is me attempting to update a variable when a number is pressed. For example when the number '1' is pressed, I want the $hash variable to updated to 'sha224'.
Is there any to achieve this using a case statement without 'select'? If not what are my alternatives?
echo
echo "Select a hashing algorithm"
echo "1 - sha224"
echo "2 - sha256"
echo "3 - sha384"
echo "4 - sha512"
while true; do
read -p "Option: [sha256]:" -e hash
case $hash in
"") hash="sha256" break 2;;
1) hash="sha224" break 2;;
2) hash="sha256" break 2;;
3) hash="sha384" break 2;;
4) hash="sha512" break 2;;
*) echo "Invalid Response: Please enter [1-4] and hit [ENTER] or hit [ENTER] to select 'sha256'";;
esac
done
Insert ; before all break.
Replace $hash with ${hash:=2} to use a default value if $hash is empty.
"") hash="sha256" break 2;; can be removed.

how to customize select loop in bash

I was wondering if is possible customize the select loop for bash.
I have this code:
select varName in list
do
case $varName in
pattern1)
command1;;
pattern2)
command2;;
pattern1)
command3;;
*)
echo "Error select option 1..3";;
esac
done
Output is something like this:
1) columbia 3) challenger 5) atlantis 7) pathfinder
2) endeavour 4) discovery 6) enterprise
#?
I would like to order the options in landscape view and also change the prompt [#?] by something else
Thanks
select displays the PS3 prompt.
You could try something like:
echo $PS3
old_PS3=$PS3
export PS3="make a selection :D"
list='columbia challenger atlantis pathfinder endeavour discovery enterprise'
select varName in $list
do
case $varName in
pattern1)
command1;;
pattern2)
command2;;
pattern1)
command3;;
*)
echo "Error select option 1..3";;
esac
done
# set PS3 back to original
export PS3=$old_PS3

Basic menu BASH script in Lubuntu

I am creating a basic menu driven BASH script with 6 options, I was wondering if someone can give me a basic template of the script?
#!/bin/bash
Option 1)
Option 2)
Option 3)
Option 4)
Option 5)
Option 6) Exit
Try the select statement. Example and template:
#!/bin/bash
select choice in opt1 opt2 opt3 opt4 opt5 exit
do
case $choice in
opt1)
sl;
fortune|cowsay -d;
break;;
opt2)
cd desktop/;
mkdir textfiles;
cd textfiles;
touch 1.txt 2.txt 3.txt;
cd ..;
tar-cvf textfiles.tar textfiles/;
break;;
opt3)
echo 'You chose opt3';;
opt4)
echo 'You chose opt4';;
opt5)
echo 'You chose opt5';;
exit)
break;;
*)
echo 'Invalid option';;
esac
done
I have inserted opt1 and opt2 as examples. Remember to use break;; if you want to exit the menu loop and choose better names than optN for the options.
Edit: I just copied opt1 and opt2 from your question. I haven't looked into them. If you need help with them, you should probably ask separate questions.

Resources