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[@]
のゼロ番目の要素の長さを取得することを意味します。args
ただし、args
空の場合はゼロ番目の要素が存在せず、再びエラーが発生します。