Random unbound variable error within function
0
votes
1
answer
7244
views
I made a function in bash and when I call it, it *crashes* with an
unbound variable
error. I don't understand cause the variables that are said to be _unbound_ are declared. Moreover, it seems to be triggered randomly like some times it crashes on line 66, some times it crashes on line 76 and some other times it crashes on line 86.
Here is the function:
#!/usr/bin/env bash
function setConfigLS() {
declare DFLT_CFG_FILE="${WEB_DOCUMENT_ROOT}/application/config/config.php"
declare DFLT_ARRAY='config'
declare cfgFile="$DFLT_CFG_FILE"
declare array="$DFLT_ARRAY"
declare value key arg
declare -a args=()
while (( $# > 0 )); do
arg="$1" && shift
case "$arg" in
--file=*)
cfgFile="${arg#*=}"
;;
-f|--file)
cfgFile="$1"
shift
;;
--value=*)
value="${arg#*=}"
;;
-v|--value)
value="$1"
shift
;;
--key=*)
key="${arg#*=}"
;;
-k|--key)
key="$1"
shift
;;
--array=*)
array="${arg#*=}"
;;
-a|--array)
array="$1"
shift
;;
-h|--help)
echo >&2 'Set a LimeSurvey configuration option.'
echo >&2 ''
echo >&2 'Usage:'
echo >&2 ' setConfigLS [options...] '
echo >&2 ' setConfigLS [options...] --value= --key='
echo >&2 ''
echo >&2 'Options:'
echo >&2 ' --file, -f LimeSurvey configuration file.'
echo >&2 " Default: ${DFLT_CFG_FILE}"
echo >&2 ' --array, -a Name of array containing the configuration.'
echo >&2 " Default: ${DFLT_ARRAY}"
echo >&2 ' --key, --k Key of the configuration option to set. (required)'
echo >&2 ' --value, -v Value of the configuration option. (required)'
echo >&2 ' --help, -h Prints this message.'
echo >&2 ''
return 0
;;
*)
args+=( "$arg" )
;;
esac
done
if [ -z "$key" ]; then # line 66: key: unbound variable
if (( ${#args} > 0 )); then
key="${args}"
args=( "${args[@]:1}" )
else
echo 'Error: --key
is required' >&2
return 1
fi
fi
if [ -z "$value" ]; then # line 76: value: unbound variable
if (( ${#args} > 0 )); then
value="${args}"
args=( "${args[@]:1}" )
else
echo 'Error: --value
is required' >&2
return 1
fi
fi
if (( ${#args} > 0 )); then # line 86: args: unbound variable
echo 'Error: too many arguments' >&2
return 1
fi
array="${array//\//\\\/}"
value="${value//$'\n'/\\$'\n'}"
ssed -Ri "$cfgFile" \
-e 's~^(\s*)('"${array}"'\s*=>\s*array\s*\()((?:\([^)]*\)|[^)])+)~\1\2\n\1 \3\n\1~'
ssed -Ri "$cfgFile" \
-e '/^\s*'"${array}"'\s*=>\s*array\s*\([^)]*$/ {
:a
n
s~^((?:\s*(?:[^,/\s]|/[^/]))+)(\s*//.*)?$~\1,\2~
s~^(\s*)//\s*('"${key//~/\\~}"'\s*=>)~\1\2~
/^\s*\)/ {
i \ '"${key}"'=>'"${value}"',
bq
}
/^\s*'"${key//\//\\\/}"'\s*=>/ {
s~>.*~>'"${value//~/\\~}"',~
bq
}
ba
:q
}'
}
I tried replacing declare value key arg
to...
declare value=
declare key=
declare arg=
...but it didn't change anthing.
I'm a little bit confused! Did I miss something? Is there something I'm not seeing?
-----
**Edit 1**
The function is called from an entrypoint script of a docker image based on ubuntu 18.04. In fact, I use [this image](https://github.com/webdevops/Dockerfile/tree/master/docker/php-apache-dev/ubuntu-18.04) .
The function's file is copied to /opt/docker/functions/set-config-ls.sh
.
Here is the script from which the function is called:
#!/usr/bin/env bash
set -eu
declare FUNC_DIR='/opt/docker/functions'
declare APP_DIR="${WEB_DOCUMENT_ROOT}"
declare DB_SETUP_PHP="/opt/docker/db_setup.php"
source "${FUNC_DIR}/tty-loggers.sh"
source "${FUNC_DIR}/yes-no.sh"
source "${FUNC_DIR}/file-env.sh"
source "${FUNC_DIR}/set-config-ls.sh"
source "${FUNC_DIR}/env-list-vars.sh"
####################################################################
########################## Setup Variables #########################
fileEnv 'LIMESURVEY_DB_TYPE' 'mysql'
fileEnv 'LIMESURVEY_DB_HOST' 'mysql'
fileEnv 'LIMESURVEY_DB_PORT' '3306'
fileEnv 'LIMESURVEY_TABLE_PREFIX' ''
fileEnv 'LIMESURVEY_ADMIN_NAME' 'Lime Administrator'
fileEnv 'LIMESURVEY_ADMIN_EMAIL' 'lime@lime.lime'
fileEnv 'LIMESURVEY_ADMIN_USER' ''
fileEnv 'LIMESURVEY_ADMIN_PASSWORD' ''
fileEnv 'LIMESURVEY_DEBUG' '0'
fileEnv 'LIMESURVEY_SQL_DEBUG' '0'
fileEnv 'MYSQL_SSL_CA' ''
fileEnv 'LIMESURVEY_USE_INNODB' ''
# if we're linked to MySQL and thus have credentials already, let's use them
fileEnv 'LIMESURVEY_DB_NAME' "${MYSQL_ENV_MYSQL_DATABASE:-limesurvey}"
fileEnv 'LIMESURVEY_DB_USER' "${MYSQL_ENV_MYSQL_USER:-root}"
if [ "${LIMESURVEY_DB_USER}" = 'root' ]; then
fileEnv 'LIMESURVEY_DB_PASSWORD' "${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}"
else
fileEnv 'LIMESURVEY_DB_PASSWORD' "${MYSQL_ENV_MYSQL_PASSWORD:-}"
fi
if [ -z "${LIMESURVEY_DB_PASSWORD}" ]; then
logError 'error: missing required LIMESURVEY_DB_PASSWORD environment variable' >&2
logError ' Did you forget to -e LIMESURVEY_DB_PASSWORD=... ?' >&2
logError '' >&2
logError ' (Also of interest might be LIMESURVEY_DB_USER and LIMESURVEY_DB_NAME.)' >&2
exit 1
fi
declare -A CONNECTION_STRINGS=(
[mysql]="mysql:host=${LIMESURVEY_DB_HOST};port=${LIMESURVEY_DB_PORT};dbname=${LIMESURVEY_DB_NAME};"
[dblib]="dblib:host=${LIMESURVEY_DB_HOST};dbname=${LIMESURVEY_DB_NAME}"
[pgsql]="pgsql:host=${LIMESURVEY_DB_HOST};port=${LIMESURVEY_DB_PORT};user=${LIMESURVEY_DB_USER};password=${LIMESURVEY_DB_PASSWORD};dbname=${LIMESURVEY_DB_NAME};"
[sqlsrv]="sqlsrv:Server=${LIMESURVEY_DB_HOST};Database=${LIMESURVEY_DB_NAME}"
)
if [ -z "${CONNECTION_STRINGS[${LIMESURVEY_DB_TYPE}]}" ]; then
logError "error: invalid database type: ${LIMESURVEY_DB_TYPE}" >&2
logError " LIMESURVEY_DB_TYPE must be either \"mysql\", \"dblib\", \"pgsql\" or \"sqlsrv\"." >&2
exit 1
fi
####################################################################
######################## Download LimeSurvey #######################
if [ ! -f "${APP_DIR}/.RELEASE_${LIMESURVEY_GIT_RELEASE}" ] || isYes "${LIMESURVEY_FORCE_FETCH}"; then
find "$APP_DIR" -maxdepth 1 -type f -name '.RELEASE_*' -delete
logInfo "Retrieving LimeSurvey... (this operation may take a while)" >&2
wget -O "/tmp/lime.tar.gz" \
--progress="$( [ -t 1 ] && echo 'bar:noscroll' || echo 'dot:mega' )" \
"https://github.com/LimeSurvey/LimeSurvey/archive/${LIMESURVEY_GIT_RELEASE}.tar.gz "
logInfo "Extracting files from archive..." >&2
tar -xzf "/tmp/lime.tar.gz" \
--strip-components=1 \
--keep-newer-files \
--exclude-vcs \
--to-command='sh -c '\''
mkdir -p "$(dirname "'"${APP_DIR}"'/$TAR_FILENAME")" &&
touch "'"${APP_DIR}"'/$TAR_FILENAME" &&
dd of="'"${APP_DIR}"'/$TAR_FILENAME" >/dev/null 2>&1 &&
echo "'"${APP_DIR}"'/$TAR_FILENAME" '\' |
xargs -I '{}' touch -t 195001010000 '{}'
chown -R "${APPLICATION_USER}:${APPLICATION_GROUP}" "$APP_DIR"
rm "/tmp/lime.tar.gz"
touch ".RELEASE_${LIMESURVEY_GIT_RELEASE}"
fi
####################################################################
######################### LimeSurvey Setup #########################
# Install BaltimoreCyberTrustRoot.crt.pem
if [ ! -f "${APP_DIR}/BaltimoreCyberTrustRoot.crt.pem" ]; then
logInfo "Downloading BaltimoreCyberTrustroot.crt.pem..."
curl -fsSLo "${APP_DIR}/BaltimoreCyberTrustRoot.crt.pem" \
"https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem "
fi
if [ ! -f "${APP_DIR}/application/config/config.php" ]; then
logWarn "No config file for LimeSurvey"
logWarn " Copying default config file..."
# Copy default config file but also allow for the addition of attributes
echo " 'attributes' => array()," |
awk '/lime_/ && c == 0 { c = 1; system("cat") } { print }' \
"${APP_DIR}/application/config/config-sample-${LIMESURVEY_DB_TYPE}.php" \
> "${APP_DIR}/application/config/config.php"
fi
# Set LimeSurvey configs
setConfigLS -a 'db' -k 'connectionString' "'${CONNECTION_STRINGS[${LIMESURVEY_DB_TYPE}]}'"
setConfigLS -a 'db' -k 'tablePrefix' "'${LIMESURVEY_TABLE_PREFIX}'"
setConfigLS -a 'db' -k 'username' "'${LIMESURVEY_DB_USER}'"
setConfigLS -a 'db' -k 'password' "'${LIMESURVEY_DB_PASSWORD}'"
setConfigLS -a 'urlManager' -k 'urlFormat' "'path'"
setConfigLS -k 'debug' "${LIMESURVEY_DEBUG}"
setConfigLS -k 'debugsql' "${LIMESURVEY_SQL_DEBUG}"
if [ -n "${MYSQL_SSL_CA}" ]; then
setConfigLS -a 'db' 'attributes' \
"array(PDO::MYSQL_ATTR_SSL_CA => '${APP_DIR//\//\\\/}\/${MYSQL_SSL_CA}',
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false)"
fi
declare cfg key val
for ENV_VAR in $(envListVars "limesurvey\."); do
val="$(envGetValue "$ENV_VAR")"
cfg="${ENV_VAR#limesurvey.}"
cfg="${cfg%%.*}"
key="${ENV_VAR#limesurvey.*.}"
setConfigLS -a "$cfg" "$key" "$val"
done
mkdir -p "${APP_DIR}/upload/surveys"
chown -R "${APPLICATION_USER}:${APPLICATION_GROUP}" \
"${APP_DIR}/tmp" "${APP_DIR}/upload" "${APP_DIR}/application/config"
####################################################################
#################### LimeSurvey Database Setup #####################
if [ -n "${LIMESURVEY_USE_INNODB}" ]; then
# If you want to use INNODB - remove MyISAM specification from LimeSurvey code
sed -i "/ENGINE=MyISAM/s/\(ENGINE=MyISAM \)//1" \
"${APP_DIR}/application/core/db/MysqlSchema.php"
fi
logInfo "Waiting for database..." >&2
while ! curl -sL "${LIMESURVEY_DB_HOST}:${LIMESURVEY_DB_PORT:-3306}"; do sleep 1; done
DBSTATUS=$(TERM=dumb php -f "$DB_SETUP_PHP" -- \
"${LIMESURVEY_DB_HOST}" "${LIMESURVEY_DB_USER}" "${LIMESURVEY_DB_PASSWORD}" \
"${LIMESURVEY_DB_NAME}" "${LIMESURVEY_TABLE_PREFIX}" "${MYSQL_SSL_CA}" \
"${APP_DIR}") &>/dev/null
if [ "${DBSTATUS}" != "DBEXISTS" ] && [ -n "${LIMESURVEY_ADMIN_USER}" ] && [ -n "${LIMESURVEY_ADMIN_PASSWORD}" ]; then
logInfo 'Database not yet populated - installing Limesurvey database' >&2
su - "${APPLICATION_USER}" \
-c php -f "${APP_DIR}/application/commands/console.php" -- \
install "${LIMESURVEY_ADMIN_USER}" "${LIMESURVEY_ADMIN_PASSWORD}" \
"${LIMESURVEY_ADMIN_NAME}" "${LIMESURVEY_ADMIN_EMAIL}" verbose
fi
if [ -f "${APP_DIR}/application/commands/UpdateDbCommand.php" ]; then
logInfo 'Updating database...' >&2
su - "${APPLICATION_USER}" -c php "${APP_DIR}/application/commands/console.php" updatedb
else
logWarn 'WARNING: Manual database update may be required!' >&2
fi
if [ -n "${LIMESURVEY_ADMIN_USER}" ] && [ -n "${LIMESURVEY_ADMIN_PASSWORD}" ]; then
logInfo 'Updating password for admin user...' >&2
su - "${APPLICATION_USER}" \
-c php -f "${APP_DIR}/application/commands/console.php" -- \
resetpassword "${LIMESURVEY_ADMIN_USER}" "${LIMESURVEY_ADMIN_PASSWORD}"
fi
Here is the output of bash --version
:
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
-----
**Edit 2**
I put what I could on github. Here is the [commit](https://github.com/DrunkenPoney/docker-limesurvey/tree/1e8983f671941622dea5e70df940eb323cae05aa) .
I'm not entirely sure but I think it should work if you clone the repo and run the launch script.
Asked by Elie G.
(136 rep)
Dec 23, 2019, 03:10 PM
Last activity: Dec 23, 2019, 04:22 PM
Last activity: Dec 23, 2019, 04:22 PM