bash does not recognize if conditions within a for loop for each element for an array of strings
Goal
I am using whiptail
to let the user insert passwords to files which are used in conjunction with envsubst
for some template files.
whiptail
checklist
in order to render stuff in whiptail
I use the following:
declare -A availableServices=(
[grafana]="Grafana Dashboard"
[influxdb]="InfluxDB v1.x TSDB"
[node-red]="Node-RED Flow UI"
[portainer]="Portainer Container Mgmt"
)
# Render TUI
function askGenerateCredential() {
local message="Set Password for particular Servicen
Press <SPACEBAR> to Select n
Press <Enter> to Skip
"
local arglist=()
# Generate a String for Whiptail Checkboxes
# FORMAT: "<INDEX> <DESCRIPTION> <OFF>"
for index in "${!availableServices[@]}";
do
# Default all Services are NOT-Selected (OFF)
arglist+=("$index" "${availableServices[$index]}" "OFF")
done
SELECTED_SERVICES+=$($WHIPTAIL --title "Available Services within Populo"
--notags --separate-output
--ok-button Next
--nocancel
--checklist "$message" $LINES $COLUMNS $(( LINES - 12 ))
-- "${arglist[@]}"
3>&1 1>&2 2>&3)
}
the SELECTED_SERVICES
is an array declared as
declare -a SELECTED_SERVICES=()
The rendering works well, however I have a specific if else
condition in my script that is unable to execute specific commands based on the selected service in the array above.
askGenerateCredential
if [ -z "$SELECTED_SERVICES" ]; then
echo "No Services were selected. Exiting..."
exit 1
else
for service in "${SELECTED_SERVICES}";
do
if [ "$service" == "influxdb" ]; then
echo "Setting Credentials for InfluxDB"
setInfluxDBCredentials
elif [ "$service" == "grafana" ]; then
echo "Setting Credentials for Grafana"
setGrafanaCredentials
elif [ "$service" == "node-red" ]; then
echo "Setting Credentials for node-RED"
setNodeRedCredentials
elif [ "$service" == "portainer" ]; then
echo "Setting Credential for Portainer"
setPortainerCredentials
fi
done
fi
Upon adding the above block, my script exits with 0
code when I select multiple values via whiptail
UI. On the contrary, when I only select one value in the UI, the respective function is called.
What am I doing wrong here? I wish that depending on the service
variable, the respective function is called and not exit the script.
Code
#!/bin/env bash
WHIPTAIL=$(which whiptail)
if [ -z $WHIPTAIL ]
then
echo "This script requires whiptail to render the TUI."
exit 1
fi
declare -a SELECTED_SERVICES=()
LINES=$(tput lines)
COLUMNS=$(tput cols)
declare -A availableServices=(
[grafana]="Grafana Dashboard"
[influxdb]="InfluxDB v1.x TSDB"
[node-red]="Node-RED Flow UI"
[portainer]="Portainer Container Mgmt"
)
function askGenerateCredential() {
local message="Set Password for particular Servicen
Press <SPACEBAR> to Select n
Press <Enter> to Skip
"
local arglist=()
# Generate a String for Whiptail Checkboxes
# FORMAT: "<INDEX> <DESCRIPTION> <OFF>"
for index in "${!availableServices[@]}";
do
# Default all Services are NOT-Selected (OFF)
arglist+=("$index" "${availableServices[$index]}" "OFF")
done
SELECTED_SERVICES+=$($WHIPTAIL --title "Available Services within Populo"
--notags --separate-output
--ok-button Next
--nocancel
--checklist "$message" $LINES $COLUMNS $(( LINES - 12 ))
-- "${arglist[@]}"
3>&1 1>&2 2>&3)
}
function setInfluxDBCredential() {
echo "set admin password env var for influxdb"
}
function setGrafanaCredential() {
echo "set admin password env var for grafana"
}
function setNodeRedCredential() {
echo "set admin password env var for node-REd"
}
function setPortainerCredential() {
echo "set password file for portainer"
}
askGenerateCredential
if [ -z "$SELECTED_SERVICES" ]; then
echo "No Services were selected. Exiting..."
exit 1
else
for service in "${SELECTED_SERVICES}";
do
if [ "$service" == "influxdb" ]; then
echo "Setting Credentials for InfluxDB"
setInfluxDBCredentials
elif [ "$service" == "grafana" ]; then
echo "Setting Credentials for Grafana"
setGrafanaCredentials
elif [ "$service" == "node-red" ]; then
echo "Setting Credentials for node-RED"
setNodeRedCredentials
elif [ "$service" == "portainer" ]; then
echo "Setting Credential for Portainer"
setPortainerCredentials
fi
done
fi
EDIT
Upon suggestion I tried ${SELECTED_SERVICES[@]}
in the for loop and added an echo "$service"
which is able to loop through the array however the if
conditions are not triggered.
I believe the logic in your askGenerateCredential()
function is not doing what you want it to do. Currently the entire output of your whiptail command is being added to the array as a single element. If you want multiple elements split at newlines you should change it to something like this:
askGenerateCredential() {
local message="Set Password for particular Servicen
Press <SPACEBAR> to Select n
Press <Enter> to Skip
"
local arglist=()
# Generate a String for Whiptail Checkboxes
# FORMAT: "<INDEX> <DESCRIPTION> <OFF>"
for index in "${!availableServices[@]}";
do
# Default all Services are NOT-Selected (OFF)
arglist+=("$index" "${availableServices[$index]}" "OFF")
done
readarray -t SELECTED_SERVICES < <("$WHIPTAIL" --title "Available Services within Populo"
--notags --separate-output
--ok-button Next
--nocancel
--checklist "$message" "$LINES" "$COLUMNS" $(( LINES - 12 ))
-- "${arglist[@]}"
3>&1 1>&2 2>&3)
}
Also you are calling SELECTED_SERVICES
as a variable instead of an array.
You need to change:
for service in "${SELECTED_SERVICES}"
to:
for service in "${SELECTED_SERVICES[@]}"
As is you will only expand the first element of the array. However as your code is written SELECTED_SERVICES
will only ever receive a single element.
See 6.7 Arrays
Additionally case would probably be better used instead of the if/elif construct. Something like:
case $service in
influxdb) echo "Setting Credentials for InfluxDB"; setInfluxDBCredentials;;
grafana) echo "Setting Credentials for Grafana"; setGrafanaCredentials;;
node-red) echo "Setting Credentials for node-RED"; setNodeRedCredentials;;
portainer) echo "Setting Credential for Portainer"; setPortainerCredentials;;
*) echo "Error; unknown option: $service" >&2;;
esac