Ich habe mir ein paar Bash-Ini-Parsing-Skripte angesehen und festgestelltDaseines wurde hier ein paar Mal verwendet, also versuche ich herauszufinden, ob es bei mir funktioniert. Es sieht so aus, als würde es die INI-Datei mehrere Male Zeile für Zeile lesen und mit jedem Durchgang schrittweise eine Funktion erstellen, die schließlich ausgewertet wird. Bei einigen Sonderzeichen funktioniert es einwandfrei, bei anderen jedoch nicht. Wenn ein Wert in der Datei ein einfaches Anführungszeichen oder ein Größer/Kleiner-als-Symbol enthält, gibt das Skript Syntaxfehler zurück. Auch andere Symbole führen zu unerwarteten Ergebnissen. Wie kann ich mit diesen Zeichen umgehen, wenn sie auftreten?
Dies ist die Funktion, die die INI analysiert.
#!/usr/bin/env bash
cfg_parser ()
{
ini="$(<$1)" # read the file
ini="${ini//[/\[}" # escape [
ini="${ini//]/\]}" # escape ]
IFS=$'\n' && ini=( ${ini} ) # convert to line-array
ini=( ${ini[*]//;*/} ) # remove comments with ;
ini=( ${ini[*]/\ =/=} ) # remove tabs before =
ini=( ${ini[*]/=\ /=} ) # remove tabs be =
ini=( ${ini[*]/\ =\ /=} ) # remove anything with a space around =
ini=( ${ini[*]/#\\[/\}$'\n'cfg.section.} ) # set section prefix
ini=( ${ini[*]/%\\]/ \(} ) # convert text2function (1)
ini=( ${ini[*]/=/=\( } ) # convert item to array
ini=( ${ini[*]/%/ \)} ) # close array parenthesis
ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick
ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2)
ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
ini[0]="" # remove first element
ini[${#ini[*]} + 1]='}' # add the last brace
eval "$(echo "${ini[*]}")" # eval the result
}
ini-Datei
[Section1]
value1=abc`def # unexpected EOF while looking for matching ``'
value2=ghi>jkl # syntax error near unexpected token `>'
value3=mno$pqr # executes ok but outputs "mnoqr"
value4=stu;vwx # executes ok but outputs "stu"
Antwort1
Die Tatsache, dass Siedürfenetwas tun bash
bedeutet nicht, dass Siesollen.
sh
(und bash
etc.) Skripte eignen sich am besten als relativ einfache Wrapper zum Starten von Programmen oder um Textverarbeitungsbefehle. Für kompliziertere Aufgaben, einschließlich der Analyse von INI-Dateien und deren Bearbeitung, sind andere Sprachen besser geeignet. Haben Sie schon einmal darüber nachgedacht, Ihr Skript in perl
oder zu schreiben python
? Beide haben gute .ini-Dateiparser – ich habe Config::INI
das Modul von Perl mehrmals verwendet, wenn ich eine INI-Datei analysieren musste.
Wenn Sie jedoch darauf bestehen, dies in Bash zu tun, sollten Sie ein assoziatives Array verwenden, anstatt einzelne Variablen festzulegen.
Beginnen Sie etwa so:
#! /bin/bash
inifile='user1074170.ini'
# declare $config to be an associative array
declare -A config
while IFS='=' read -r key val ; do
config["$key"]="$val"
done < <(sed -E -e '/^\[/d
s/#.*//
s/[[:blank:]]+$|^[[:blank:]]+//g' "$inifile" )
# now print out the config array
set | grep '^config='
Das sed
Skript löscht die [Section1]
Zeile (genauer gesagt alle Zeilen, die mit einer öffnenden eckigen Klammer beginnen [
- in einer INI-Datei mit mehreren Abschnitten sollten Sie dies anders handhaben [1] ) und entfernt Kommentare sowie führende und nachfolgende Leerzeichen. Die while
Schleife liest jede Zeile ein, verwendet dabei =
als Feldtrennzeichen und weist den Inhalt den Variablen $key und $val zu, die dann dem Array $config hinzugefügt werden.
Ausgabe:
config=([value1]="abc\`def" [value3]="mno\$pqr" [value2]="ghi>jkl" [value4]="stu;vwx" )
Sie können die Array-Einträge später in Ihrem Skript wie folgt verwenden:
$ echo value1 is "${config[value1]}"
value1 is abc`def
$ [ "${config[value4]}" = 'stu;vwx' ] && echo true
true
[1] awk
oder perl
haben Sie bequeme und einfache Möglichkeiten, Dateien im "Absatz"-Modus zu lesen. Ein Absatz ist definiert als ein Textblock, der von anderen Textblöcken durch eine oder mehrere Leerzeilen getrennt ist.
Um beispielsweise nur mit zu arbeiten [Section1]
, fügen Sie das awk
folgende Skript unmittelbar vor dem sed
Skript ein, das in die while
obige Schleife einspeist:
awk -v RS= -v ORS='\n\n' '/\[Section1\]/' "$inifile" | sed ...
(und natürlich "$inifile"
vom Ende der sed
Befehlszeile aus entfernen – Sie möchten die Datei nicht erneut eingeben, nachdem Sie sich die Mühe gemacht haben, nur [Section1]
daraus zu extrahieren).
Die Einstellung ORS
ist nicht unbedingt erforderlich, wenn Sie nur einen Abschnitt aus der INI-Datei extrahieren. Sie ist jedoch nützlich, um die Absatztrennung beizubehalten, wenn Sie zwei oder mehr Abschnitte extrahieren.
Antwort2
Ich weiß, dass die Antwort unvollständig ist, aber MySQL.lns
in augeas scheint das meiste davon analysieren zu können. In augtool
:
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> set /augeas/load/testini/lens "MySQL.lns"
augtool> load
augtool> ls /files/root/
.ssh/ test.ini/
augtool> ls /files/root/test.ini
target/ = Section1
augtool> ls /files/root/test.ini/target/
value1/ = abc`def
value2/ = ghi>jkl
value3/ = mno$pqr
value4/ = stu
Das einzige, bei dem es schiefgelaufen ist, ist das letzte, und um ehrlich zu sein, glaube ich nicht, dass das ein Fehler ist. In .ini
Dateien markiert das Semikolon den Anfang eines Kommentars. Ich möchte auch fragen, ob Ihre Daten tatsächlich so aussehen.
Wenn dies der Fall ist, können Sie sed
vorher einfach etwas tun, das ;
auf einen unbenutzten Zeichenwert gesetzt wird, und es dann nachträglich zurücktransformieren. Letztendlich werden Sie jedoch einige Standards benötigen, damit die Datei eine erkennbare Struktur haben kann.
BEARBEITEN:
Ich habe es mit dem PHP-Objektiv ausprobiert und solange die Werte in Anführungszeichen standen, funktionierte alles:
[root@vlzoreman ~]# augtool
augtool> set /augeas/load/testini/lens "PHP.lns"
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> load
augtool> ls /files/root/test.ini/Section1/
value1 = abc`def
value2 = ghi>jkl
value3 = mno$pqr
value4 = stu;vwx
Ansonsten ist es so weit gekommen wie die MySQL-Linse.
BEARBEITEN #2:
Ich bin sicher, dass es eine einfachere Möglichkeit gibt, dies zu schreiben, aber dies ist ein Verwendungsbeispiel:
[root@vlp-foreman ~]# bash bash.sh
Values for: Section1:
:: value1 is abc`def
:: value2 is ghi>jkl
:: value3 is mno$pqr
:: value4 is stu;vwx
Values for: Section2:
:: value1 is abc`def
Das Skript lautet:
#!/bin/bash
sections=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini | cut -f1 -d/)
for currentSection in $sections; do
echo "Values for: $currentSection:"
fields=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini/$currentSection | awk '{print $1}')
for currentField in $fields; do
currentValue=$(augtool -A --transform "PHP.lns incl /root/test.ini" print /files/root/test.ini/$currentSection/$currentField | cut -f2 -d=)
currentValue=$(echo $currentValue | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' | sed -e 's/^"//' -e 's/"$//')
echo -e "\t:: $currentField is $currentValue"
done
done
Antwort3
schau dir mal an crudini
:https://www.pixelbeat.org/programs/crudini/
Unter Ubuntu können Sie es installieren, um sudo apt install crudini
einen Wert aus einer INI-Datei zu lesen. Führen Sie dazu Folgendes aus:
$ value1=$(crudini --get "crudini.ini" "Section1" "value1")
Crudini unterstützt mehrere INI-Dateiformate und verarbeitet Sonderzeichen:
crudini.ini
[Section1]
value1=abc`def
value2=ghi>jkl
value3=mno$pqr
value4=stu;vwx
Werte ablesen
$ for i in {1..4}; do crudini --get "crudini.ini" "Section1" "value$i"; done
abc`def
ghi>jkl
mno$pqr
stu;vwx
$