I want to issue a bash command similar to this:
whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 \
1 production off \
2 localhost on
Whiptail is rather particular about how the radio list values are specified. They must be provided each on their own line, as shown. Here is a good article on this question.
The list of databases is available in a variables called DBS
, and ACTIVE_DB
is the radiolist item to highlight in the whiptail dialog.
Here is my current effort for building the command line. It is probably way too convoluted.
DBS="production localhost"
ACTIVE_DB="localhost"
DB_COUNT="$( echo "$DBS" | wc -w )"
DB_LIST="$(
I=1
echo ""
for DB in $DBS; do
SELECTED="$( if [ "$DB" == "$ACTIVE_DB" ]; then echo " on"; else echo " off"; fi )"
SLASH="$( if (( $I < $DB_COUNT )); then echo \\; fi )"
echo " $I $DB $SELECTED $SLASH"
echo ""
I=$(( I + 1 ))
done
)"
OPERATION="whiptail \
--title \"Select Database\" \
--radiolist \
\"Select Database:\" \
10 80 $DB_COUNT \"${DB_LIST[@]}\""
eval "${OPERATION}"
I get fairly close. As you can see, the expansion contains single quotes that mess things up, and backslashes are missing at some EOLs:
set -xv
++ whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 '
1 production off
2 localhost on '
The solution needs to provide a way to somehow know which selection the user made, or if they pressed ESC. ESC usually sets the return code to 255, so that should not be difficult, however this problem gets really messy when trying to retrieve the value of the user-selected radiolist item.
The following follows best practices set out in BashFAQ #50:
# note that lower-case variable names are reserved for application use by POSIX
# see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
active_db="localhost"
dbs=( production localhost ) # using an array, not a string, means ${#dbs[@]} counts
# initialize an array with our explicit arguments
whiptail_args=(
--title "Select Database"
--radiolist "Select Database:"
10 80 "${#dbs[@]}" # note the use of ${#arrayname[@]} to get count of entries
)
i=0
for db in "${dbs[@]}"; do
whiptail_args+=( "$((++i))" "$db" )
if [[ $db = "$active_db" ]]; then # only RHS needs quoting in [[ ]]
whiptail_args+=( "on" )
else
whiptail_args+=( "off" )
fi
done
# collect both stdout and exit status
# to grok the file descriptor switch, see https://stackoverflow.com/a/1970254/14122
whiptail_out=$(whiptail "${whiptail_args[@]}" 3>&1 1>&2 2>&3); whiptail_retval=$?
# display what we collected
declare -p whiptail_out whiptail_retval
While I don't have whiptail
handy to test with, the exact invocation run by the above code is precisely identical to:
whiptail --title "Select Database" \
--radiolist "Select Database:" 10 80 2 \
1 production off \
2 localhost on
...as a string which, when eval
ed, runs the precise command can be generated with:
printf '%q ' whiptail "${whiptail_args[@]}"; echo