Ich bin ein paar Wochen in Bash-Scripting und ich habe noch nicht weit genug fortgeschritten, um meinen Kopf um dieses Problem zu wickeln. Jede Hilfe wäre willkommen!Wie können Schlüsselwertpaare aus einer Datei extrahiert werden, wenn sich Werte über mehrere Zeilen erstrecken?
Ich habe einen „script.conf“ Datei, die Folgendes enthält:
key1=value1
key2=${HOME}/Folder
key3=("k3v1" "k3 v2" "k3v3")
key4=("k4v1"
"k4 v2"
"k4v3"
)
key5=value5
#key6="Do Not Include Me"
In einem Bash-Skript, ich den Inhalt dieser script.conf Datei in ein Array lesen möchten. Ich habe gelernt, wie man mit den Szenarien für die Schlüssel 1, 2, 3 und 5 umgeht, aber das key4-Szenario wirft einen Schraubenschlüssel hinein, der sich über mehrere Zeilen erstreckt.
Ich habe die Verwendung von sed -n '/=\s*[(]/,/[)]/{/'
erforschen die Erfassung key4 und seinen Wert hat, aber ich kann nicht herausfinden, wie dies zu mischen, so dass die anderen Tasten auch in den Spielen erfaßt werden. Die Bereichssyntax ist auch neu für mich, also habe ich nicht herausgefunden, wie man den Schlüssel/Wert trennt. Ich habe das Gefühl, dass es einen einfachen Regex gibt, der das erreicht, was ich will ... im Klartext: "Finde und gruppiere das Muster ^(.*)=
(für den Schlüssel), dann gruppiere alles nach dem '=' char, bis ein weiterer ^(.*)=
Treffer gefunden wird spülen und wiederholen ". Ich denke, wenn ich das tue, muss ich die While-Read-Zeile ändern, um die Schlüssel/Wert-Trennung für mich nicht zu handhaben (ich werde das untersuchen, während ich auf eine Antwort warte). BTW, ich denke, eine Lösung, wo der Wert von key4 abgeflacht ist (neue Zeilen entfernt) wäre akzeptabel; Ich weiß, dass ich für key3 den Wert als String speichern und später in ein Array konvertieren muss, wenn ich darüber iterieren möchte, da ein Array-Element anscheinend keine Liste enthalten kann.
Bin ich auf dem richtigen Weg mit sed
oder ist das ein Job für awk
oder ein anderes Werkzeug? (Ich habe mich noch nicht in awk gewagt). Gibt es einen einfacheren Ansatz, den ich vermisse, weil ich zu tief in den Wald hinein bin (wie die Zeile while read
in der LoadConfigFile-Funktion zu ändern)?
Hier ist der Code, den ich in bisher haben script.sh für die Verarbeitung und die anderen Paare in die $ config Array erfassen:
__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
Wie ich schon erwähnt, ich bin nur zum Start lerne Bash und Linux Scripting allgemein, also wenn du siehst, dass ich auch in anderen Bereichen meines Codes einige Tabus mache, gib bitte Feedback in den Kommentaren ... Ich möchte keine schlechten Gewohnheiten früh anfangen auf :-).
* Wenn es darauf ankommt, ist das Betriebssystem Ubuntu 14.04.
EDIT: Wie gewünscht, nachdem die script.conf Datei zu lesen, würde ich für die Elemente in $config[@]
gerne folgenden gleichwertig sein:
typeset -A config #init config array
config=(
[key1]="value1"
[key2]="${HOME}/Folder"
[key3]="(\"k3v1\" \"k3 v2\" \"k3v3\")"
[key4]="(\"k4v1\" \"k4 v2\" \"k4v3\")"
[key5]="value5"
)
Ich mag die konvertieren können, Werte der Elemente ‚key4‘ und ‚key3‘ in ein Array und über sie die gleiche Art und Weise in den folgenden Code iteriert:
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
ich glaube nicht, dass es wichtig ist, wenn \ n für key4 die va erhalten bleibt lue oder nicht ... das hängt davon ab, ob declare
ein Problem damit hat.
Ist das Sourcing der Konfigurationsdatei keine Option? –
Anstatt eine fehlerhafte Teilmenge eines Bash-Parsers zu implementieren, warum sollte man die Datei nicht _sourcen_? –
Sind Sie mit der Shell eingeschränkt? Für solche Aufgaben würde ich eine andere * Sprache * (Python, Perl, ...) verwenden. – MarcoS