함수 내 무작위 언바운드 변수 오류

함수 내 무작위 언바운드 변수 오류

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' '[email protected]'
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에 올렸습니다. 여기있어범죄.

확실하지는 않지만 저장소를 복제하고 시작 스크립트를 실행하면 작동할 것이라고 생각합니다.

답변1

value, 또는 key다음에 대한 값은 설정 되지 않습니다 arg.

declare value key arg

따라서 key할당에 도달하지 못한 경우:case

while (( $# > 0 )); do
    arg="$1" && shift
    case "$arg" in
        --key=*)
            key="${arg#*=}"
        ;;

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[@]의 0번째 요소 길이를 가져오는 것을 의미합니다 . args하지만 args비어 있으면 0번째 요소가 존재하지 않고 다시 오류가 발생합니다.

관련 정보