我已经花了几周的时间来进行bash脚本编写,而且我还没有达到足够的进展来解决这个问题。任何帮助将不胜感激!
我有一个“ script.conf ”文件,其中包含以下内容:
key1=value1
key2=${HOME}/Folder
key3=( "k3v1" "k3 v2" "k3v3")
key4=( "k4v1"
"k4 v2"
"k4v3"
)
key5=value5
#key6="Do Not Include Me"
在bash脚本中,我想将此script.conf文件的内容读入数组。我已经学会了如何处理键1,2,3和5的场景,但是 key4场景会突破它,并且它跨越多行。
我一直在探索使用sed -n '/=\s*[(]/,/[)]/{/'
来捕获key4及其值,但我无法弄清楚如何混合它以便在匹配中捕获其他键。范围语法对我来说也是新的,所以我还没弄清楚如何分离键/值。我觉得有一个简单的正则表达式可以实现我想要的...在纯文本中:“查找并分组模式^(.*)=
(对于密钥),然后将所有内容分组到'='char之后直到另一个发现^(.*)=
匹配,冲洗并重复“。我想如果我这样做,我需要更改while读取行,以便不为我处理键/值分离(我会在等待响应时查看这个)。顺便说一下,我认为key4的值被平整(删除新行)的解决方案是可以接受的;我知道对于key3我必须将值存储为字符串,然后在我想迭代它时将其转换为数组,因为数组元素显然不能包含列表。
我是sed
的正确路径还是awk
或其他工具的工作? (我还没敢冒险进入awk)。是否有一种更容易的方法,因为我太深入森林了(比如更改LoadConfigFile函数中的while read
行)?
以下是我目前在 script.sh 中处理和捕获其他对到$ config数组中的代码:
__AppDir=$(dirname $0)
__AppName=${__ScriptName%.*}
typeset -A config #init config array
config=( #Setting Default Config values
[key1]="defaultValue1"
[key2]="${HOME}/defaultFolder"
[QuietMode]=0
[Verbose]=0 #Ex. Usage: [[ "${config[Verbose]}" -gt 0 ]] && echo ">>>Debug print"
)
function LoadConfigFile() {
local cfgFile="${1}"
shopt -s extglob #Needed to remove trailing spaces
if [ -f ${cfgFile} ]; then
while IFS='=' read -r key value; do
if [[ "${key:0:1}" == "#" ]]; then
#echo "Skipping Comment line: ${key}"
elif [ "${key:-EMPTY}" != "EMPTY" ]; then
value="${value%%\#*}" # Delete in-line, right comments
value="${value%%*( )}" # Delete trailing spaces
value="${value%%( )*}" # Delete leading spaces
#value="${value%\"*}" # Delete opening string quotes
#value="${value#\"*}" # Delete closing string quotes
#Manipulate any variables included in the value so that they can be expanded correctly
# - value must be stored in the format: "${var1}". `backticks`, "$var2", and "doubleQuotes" are left as is
value="${value//\"/\\\"}" # Escape double quotes for eval
value="${value//\`/\\\`}" # Escape backticks for eval
value="${value//\$/\\\$}" # Escape ALL '$' for eval
value="${value//\\\${/\${}" # Undo the protection of '$' if it was followed by a '{'
value=$(eval "printf '%s\n' \"${value}\"")
config[${key}]=${value} #Store the value into the config array at the specified key
echo " >>>DBG: Key = ${key}, Value = ${value}"
#else
# echo "Skipped Empty Key"
fi
done < "${cfgFile}"
fi
}
CONFIG_FILE=${__AppDir}/${__AppName}.conf
echo "Config File @ ${CONFIG_FILE}"
LoadConfigFile ${CONFIG_FILE}
#Print elements of $config
echo "Script Config Values:"
echo "----------------------------"
for key in "${!config[@]}"; do #The '!' char gets an array of the keys, without it, we would get an array of the values
printf " %-20s = %s\n" "${key}" "${config[${key}]}"
done
echo "------ End Script Config ------"
#To convert to an array...
declare -a valAsArray=${config[RequiredAppPackages]} #Convert the value from a string to an array
echo "Count = ${#valAsArray[@]}"
for itemCfg in "${valAsArray[@]}"; do
echo " item = ${itemCfg}"
done
正如我之前提到的,我只是开始学习bash和Linux脚本一般,所以如果你看到我在代码的其他方面做了一些禁忌的话,请随时提供反馈意见。评论......我不想在早期开始养成坏习惯: - )。
*如果重要,操作系统是Ubuntu 14.04。
修改
根据要求,在阅读script.conf文件后,我希望$config[@]
中的元素等同于以下内容:
typeset -A config #init config array
config=(
[key1]="value1"
[key2]="${HOME}/Folder"
[key3]="( \"k3v1\" \"k3 v2\" \"k3v3\" )"
[key4]="( \"k4v1\" \"k4 v2\" \"k4v3\" )"
[key5]="value5"
)
我希望能够将元素'key4'和'key3'的值转换为数组,并在以下代码中以相同的方式迭代它们:
declare -a keyValAsArray=${config[keyN]} #Convert the value from a string to an array
echo "Count = ${#keyValAsArray[@]}"
for item in "${keyValAsArray[@]}"; do
echo " item = ${item}"
done
如果为了key4的值而保留\ n,我认为这不重要......这取决于declare
是否存在问题。
答案 0 :(得分:0)
shell是一种环境,可以使用语言调用工具来对这些调用进行排序。它不是操纵文本的工具。用于操作文本的标准UNIX工具是awk。试图操作shell中的文本是一个坏习惯,请参阅why-is-using-a-shell-loop-to-process-text-considered-bad-practice了解一些原因
你仍然没有发布填充配置数组的预期结果,所以我不确定,但我认为这是你想要的:
$ cat tst.sh
declare -A config="( $(awk '
{ gsub(/^[[:space:]]+|([[:space:]]+|#.*)$/,"") }
!NF { next }
/^[^="]+=/ {
name = gensub(/=.*/,"",1)
value = gensub(/^[^=]+=/,"",1)
n2v[name] = value
next
}
{ n2v[name] = n2v[name] OFS $0 }
END {
for (name in n2v) {
value = gensub(/"/,"\\\\&","g",n2v[name])
printf "[%s]=\"%s\"\n", name, value
}
}
' script.conf
) )"
declare -p config
$ ./tst.sh
declare -A config='([key5]="value5" [key4]="( \"k4v1\" \"k4 v2\" \"k4v3\" )" [key3]="( \"k3v1\" \"k3 v2\" \"k3v3\")" [key2]="/home/Ed/Folder" [key1]="value1" )'
以上使用GNU awk for gensub(),而其他awks则使用[g] sub()代替。