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번째 요소가 존재하지 않고 다시 오류가 발생합니다.