On Sat, Aug 31, 2019 at 07:52:23PM +0100, Paul Sutton wrote: > #!/bin/bash > OPTIONS="Update List Upgrade Autoremove Clean Quit" > select opt in $OPTIONS; do
:-( :-( Please don't abuse string variables to hold lists in bash. Bash has array variables. Use an array to hold a list. > elif [ "$opt" = "Upgrade" ] ; then > echo "Upgrade packages" > apt upgrade -y > elif [ "$opt" = "Autoremove" ] ; then > echo "Autoremove packages" > apt autoremove You might want to learn about the case command. > I am now trying to create a checkbox option menu so that the user can > choose which options are needed then when pressing ok these are executed > in order. > > > whiptail --title "Check list example" --checklist \ > "Choose user's permissions" 20 78 4 \ > "NET_OUTBOUND" "Allow connections to other hosts" ON \ > "NET_INBOUND" "Allow connections from other hosts" OFF \ > "LOCAL_MOUNT" "Allow mounting of local devices" OFF \ > "REMOTE_MOUNT" "Allow mounting of remote devices" OFF > > I am just struggling to figure out how to : > > take the above, if the user chooses say 1,2 and 4 then the commands > associated with those options are executed. OK, let's start from the beginning. First, we have to figure out which dialog/whiptail subcommand you're using and how it *works*, and then write the script around that. You're using whiptail --checklist, apparently, so let's experiment to find out how that one works. First I'll type out a sample command and run it and see what happens: wooledg:~$ whiptail --checklist "Choose wisely" 20 78 4 "NET_OUT" "Allow out" ON "NET_IN" "Allow in" OFF "LOCAL_MT" "Local mount" OFF "REMOTE_MT" "Remote mount" OFF After pressing Enter, and then selecting options 1, 2 and 4 as you indicated, my terminal looks like this: wooledg:~$ whiptail --checklist "Choose wisely" 20 78 4 "NET_OUT" "Allow out" ON "NET_IN" "Allow in" OFF "LOCAL_MT" "Local mount" OFF "REMOTE_MT" "Remote mount" OFF "NET_OUT" "NET_IN" "REMOTE_MT"wooledg:~$ So, it wrote the string ... "NET_OUT" "NET_IN" "REMOTE_MT" ... WITH the quotes (!!!!1one), to either stdout or stderr. We need to figure out which one it was. So I'll add a redirection to the command, and try again: wooledg:~$ whiptail --checklist "Choose wisely" 20 78 4 "NET_OUT" "Allow out" ON "NET_IN" "Allow in" OFF "LOCAL_MT" "Local mount" OFF "REMOTE_MT" "Remote mount" OFF 2>foo And after that: wooledg:~$ whiptail --checklist "Choose wisely" 20 78 4 "NET_OUT" "Allow out" ON "NET_IN" "Allow in" OFF "LOCAL_MT" "Local mount" OFF "REMOTE_MT" "Remote mount" OFF 2>foo wooledg:~$ cat foo "NET_OUT" "NET_IN" "REMOTE_MT"wooledg:~$ So, it wrote the string '"NET_OUT" "NET_IN" "REMOTE_MT"' to stderr, with no trailing newline. All right. It's not ideal, but we can live with it. Since you've chosen simple all-alphabetic strings as your selection keys, we can simply strip out all those quote characters, and then split it into words. Here's your script. It pretty much hits the limits of what bash can comfortably do. If you need this to be *any* fancier or prettier than it is, you should rewrite it in a better language. (I added a few more comments than I would've used in a real script, because it's intended as a teaching example. It would be slightly shorter with some of the comments and blank lines removed.) #!/bin/bash # Associative arrays to map our codename keys to their labels, to their # default states in the checklist, and to their action commands. # We need a non-associative array to hold the keys so that their order is # preserved in at least one place. The order of the keys in an associative # array is not preserved. keys=(NET_OUTBOUND NET_INBOUND LOCAL_MOUNT REMOTE_MOUNT) declare -A label label=( [NET_OUTBOUND]="Allow connections to other hosts" [NET_INBOUND]="Allow connections from other hosts" [LOCAL_MOUNT]="Allow mounting of local devices" [REMOTE_MOUNT]="Allow mounting of remote devices" ) declare -A default default=( [NET_OUTBOUND]=ON [NET_INBOUND]=OFF [LOCAL_MOUNT]=OFF [REMOTE_MOUNT]=OFF ) declare -A action action=( [NET_OUTBOUND]=net_outbound [NET_INBOUND]=net_inbound [LOCAL_MOUNT]=local_mount [REMOTE_MOUNT]=remote_mount ) # Functions to be called for each selection. net_outbound() { : your code here echo "for testing: net_outbound was chosen" } net_inbound() { : your code here echo "for testing: net_inbound was chosen" } local_mount() { : your code here echo "for testing: local_mount was chosen" } remote_mount() { : your code here echo "for testing: remote_mount was chosen" } # Now, the checklist menu. # Build up the argument list dynamically from the keys and their associated # labels and default states. args=( --title "Check list example" --checklist "Choose user's permissions" 20 78 4 ) for k in "${keys[@]}"; do args+=("$k" "${label[$k]}" "${default[$k]}") done result=$(whiptail "${args[@]}" 2>&1 1>/dev/tty) || exit # Now strip those horribly stupid literal quote characters from the result. result=${result//\"/} # Now split it into a list of codename keys. read -ra results <<< "$result" # Now iterate over that list, and run the action assigned to each codename. for k in "${results[@]}"; do if [[ ! ${action[$k]} ]]; then echo "internal error: unrecognized selection '$k'" >&2 continue fi "${action[$k]}" done