Bash
函式內的隨機未綁定變數錯誤
我在 bash 中創建了一個函式,當我呼叫它時,它會因錯誤而崩潰
unbound variable
。我不明白,因為聲明了被稱為未綁定的變數。此外,它似乎是隨機觸發的,有時在第 66 行崩潰,有時在第 76 行崩潰,有時在第 86 行崩潰。這是功能:
#!/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...] <KEY> <VALUE>' echo >&2 ' setConfigLS [options...] --value=<VALUE> --key=<KEY>' echo >&2 '' echo >&2 'Options:' echo >&2 ' --file, -f <CONFIG_FILE> LimeSurvey configuration file.' echo >&2 " Default: ${DFLT_CFG_FILE}" echo >&2 ' --array, -a <ARRAY> Name of array containing the configuration.' echo >&2 " Default: ${DFLT_ARRAY}" echo >&2 ' --key, --k <KEY> Key of the configuration option to set. (required)' echo >&2 ' --value, -v <VALUE> 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[0]}" 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[0]}" 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 }' }
我嘗試替換
declare value key arg
為…declare value= declare key= declare arg=
…但它並沒有改變任何東西。
我有點困惑!我錯過了什麼?有什麼我沒看到的嗎?
編輯 1
該函式是從基於 ubuntu 18.04 的 docker 映像的入口點腳本呼叫的。事實上,我使用這個圖像。
函式的文件被複製到
/opt/docker/functions/set-config-ls.sh
.這是呼叫該函式的腳本:
#!/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
這是輸出
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 <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
編輯 2
我把我能做的都放在了 github 上。這是送出。
我不完全確定,但我認為如果您複製儲存庫並執行啟動腳本,它應該可以工作。
這不會為任何
value
,key
或設置值arg
:declare value key arg
因此,如果未達到
key
in 的分配:case
while (( $# > 0 )); do arg="$1" && shift case "$arg" in --key=*) key="${arg#*=}" ;;
then
key
在循環之後仍將被取消設置(“未綁定”),並且由於腳本具有set -u
,因此在使用時會引發錯誤。if [ -z "$key" ]; then # line 66: key: unbound variable
將變數初始化為空字元串(如
declare key= value= arg=
)將消除該問題。但是,您也可以參考
args
:if [ -z "$key" ]; then # line 66: key: unbound variable if (( ${#args} > 0 )); then
請注意,這指的是
args
,不是args[@]
,您取的是數組第零個元素的長度args
,而不是其中的元素數。但如果args
為空,則第零個元素不存在,這又是一個錯誤。