Der beste Weg, um eine Konfigurationsdatei in Bash zu lesen

23

Was ist der beste Weg, um eine Konfigurationsdatei in Bash zu lesen?
Sie haben beispielsweise ein Skript und möchten nicht jedes Mal, wenn Sie das Skript aufrufen, die gesamte Konfiguration manuell eingeben.

Edit 1: Ich glaube, ich habe es nicht klargestellt, also: Ich möchte ... Ich habe eine Konfigurationsdatei, die so aussieht

variable_name value  
variable_name value ...  

und das möchte ich lesen. Ich weiß, ich könnte es einfach nach den Argumenten durchsuchen, nach denen ich suche, oder so ... aber vielleicht gibt es einen intelligenteren Weg :)

IcyIcyIce
quelle
2
Sie müssen zeigen, welche Art von Konfiguration Sie meinen. Geben Sie ein Beispiel.
muru
Siehe auch eine sehr ähnliche Frage zu Unix & Linux StackExchange.
Michael

Antworten:

38

Wie mbiber sagte, eine sourceandere Datei. Zum Beispiel wäre Ihre Konfigurationsdatei (sagen wir some.config):

var1=val1
var2=val2

Und Ihr Skript könnte so aussehen:

#! /bin/bash

# Optionally, set default values
# var1="default value for var1"
# var1="default value for var2"

. /path/to/some.config

echo "$var1" "$var2"

Die vielen Dateien in der /etc/defaultRegel dienen in ähnlicher Weise als Konfigurationsdateien für andere Shell-Skripte. Ein sehr verbreitetes Beispiel aus Beiträgen hier ist /etc/default/grub. Diese Datei wird zum Festlegen von Konfigurationsoptionen für GRUB verwendet, da grub-mkconfiges sich um ein Shell-Skript handelt, das diese Quelle verwendet:

sysconfdir="/etc"
#…
if test -f ${sysconfdir}/default/grub ; then
  . ${sysconfdir}/default/grub
fi

Wenn Sie die Konfiguration des Formulars wirklich bearbeiten müssen:

var1 some value 1
var2 some value 2

Dann könnten Sie etwas tun wie:

while read var value
do
    export "$var"="$value"
done < /path/to/some.config

(Sie könnten auch so etwas tun eval "$var=$value", aber das ist riskanter als die Beschaffung eines Skripts. Sie könnten das versehentlich leichter brechen als eine beschaffte Datei.)

muru
quelle
Das ist eine großartige Möglichkeit, ich könnte sed-Ersatz-Whitespace für "=" verwenden
IcyIcyIce
1
@IcyIcyIce Einfach nicht. Warum kannst du es nicht =von Anfang an schreiben ?
Muru
1
@IcyIcyIce So soll es sein. Sie können Shell-Code in den verschiedenen Dateien verwenden /etc/default- und meistens gut gebrauchen. Wenn Ihr ahnungsloser Benutzer Zugriff auf die Konfiguration für etwas hat, das als Root ausgeführt wird, ist dies bereits ein verlorener Grund.
Muru
1
@IcyIcyIce Lassen Sie Ihre Lehrer klären, was sie wollen. Ein Teil des Lernens, Software zu entwickeln, besteht darin, die Anforderungen klar zu kennen.
muru
1
@IcyIcyIce siehe Update.
muru
4

Offensichtlich bin ich nicht der bash Spezialist, aber das Konzept sollte in der von Ihnen verwendeten Sprache nicht anders sein:

Ein Beispiel

Im Beispiel unten können Sie ein (sehr) einfaches Skript verwenden entweder Satz eine Zeichenfolge, oder drucken Sie eine Zeichenfolge, als Satz in Ihrer Konfigurationsdatei:

#!/bin/bash

# argument to set a new string or print the set string
arg=$1
# possible string as second argument
string=$2
# path to your config file
configfile="$HOME/stringfile"

# if the argument is: "set", write the string (second argument) to a file
if [ "$arg" == "set" ]
then
echo "$string" > $configfile 
# if the argunment is "print": print out the set string, as defined in your file
elif [ "$arg" == "print" ]
then 
echo "$( cat $configfile )"
fi

Dann

  • So legen Sie eine Zeichenfolge in Ihrer Konfigurationsdatei fest:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Anschließend drucken Sie den in Ihrer "Konfigurationsdatei" definierten String aus:

    $ '/home/jacob/Bureaublad/test.sh' print
    Een aap op een fiets, hoe vind je zoiets?

Natürlich müssen Sie in einem echten angewandten Skript eine Menge Dinge hinzufügen, um sicherzustellen, dass die Argumente korrekt sind, um zu entscheiden, was zu tun ist, wenn die Eingabe falsch ist, die Einstellungsdatei nicht existiert usw., aber:

Das ist die Grundidee

Jacob Vlijm
quelle
danke, ich aktualisiere gerade die Frage, von der ich glaube, dass ich sie nicht klargestellt habe ... aber in einfachen Fällen würde dies wie ein Zauber von c funktionieren
IcyIcyIce
4

Verwenden Sie sourceoder ., um eine Datei zu laden.

source /path/to/file

oder

. /path/to/file

Es wird außerdem empfohlen, vor dem Laden zu prüfen, ob die Datei vorhanden ist, da Sie Ihr Skript nicht weiter ausführen möchten, wenn keine Konfigurationsdatei vorhanden ist.

mbiber
quelle
0

Ich benutze dieses ...

#!/bin/bash

CFG_FILE=/etc/test.conf
CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval "$CFG_CONTENT"

Conf-Datei wird mit sed analysiert und dann als einfache Variablenzuweisung ausgewertet

Erste Sed Parsing Schlüsselwerte (unterstützt auch = mit Leerzeichen umgeben)

In der zweiten Zeile werden Leerzeichen um das Zeichen = für die gültige Variablenzuordnung entfernt

Weitere sed Behandlung kann hinzugefügt werden

Alle anderen nicht übereinstimmenden Texte in der Conf-Datei werden entfernt (einschließlich # oder; Kommentar und andere).

Beachten Sie, dass einzeilige Shell-Befehle auch aus dieser Konfigurationsdatei ausgewertet werden können!

smARTin
quelle
1
Nutzloser Gebrauch voncat . Warum rufen Sie sedzweimal hintereinander auf? Sie können sedBefehle wie sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster
Außerdem sedgeneriert dieser Befehl eine leere Ausgabe für die Beispielkonfigurationsdateieinträge in der Frage. -1
David Foerster
1
Eine weitere mögliche Verbesserung: Verwenden Sie den .Befehl und die Prozessumleitung anstelle von temporären Variablen, um die Ausgabe des Unterprozesses . <(sed ... "$CFG_FILE")
David Foerster,
Natürlich verwendet mein Beispiel key = value wie die Konfigurationsdatei. Es ist eine bessere Praxis als "Schlüsselwert". Mit key = value funktioniert mein Beispiel. Ich gebe zu, dass Ihre Verkettung von sed-Befehlen besser ist, aber der Quellbefehl erwartet eine Datei, damit wir Folgendes verwenden können eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE"):, um besser zu verstehen, was dort vorgeht.
Smartin
Ja, .erwartet eine Datei und die Prozessersetzung wird zu einer Datei erweitert. . <(echo echo foo)funktioniert wie erwartet in Bash v4.3.11. In kleinen Beispielen spielt es wahrscheinlich keine Rolle. Ich würde es jedoch vorziehen, nicht mehrere Kilobyte durch Befehlsersetzung zu übergeben.
David Foerster
0
#------------------------------------------------------------------------------
# parse the ini like $0.$host_name.cnf and set the variables
# cleans the unneeded during after run-time stuff. Note the MainSection
# courtesy of : http://mark.aufflick.com/blog/2007/11/08/parsing-ini-files-with-sed
#------------------------------------------------------------------------------
doParseConfFile(){
    # set a default cnfiguration file
    cnf_file="$run_unit_bash_dir/$run_unit.cnf"

    # however if there is a host dependant cnf file override it
    test -f "$run_unit_bash_dir/$run_unit.$host_name.cnf" \
    && cnf_file="$run_unit_bash_dir/$run_unit.$host_name.cnf"

    # yet finally override if passed as argument to this function
    # if the the ini file is not passed define the default host independant ini file
    test -z "$1" || cnf_file=$1;shift 1;


    test -z "$2" || ini_section=$2;shift 1;
    doLog "DEBUG read configuration file : $cnf_file"
    doLog "INFO read [$ini_section] section from config file"

    # debug echo "@doParseConfFile cnf_file:: $cnf_file"
    # coud be later on parametrized ...
    test -z "$ini_section" && ini_section='MAIN_SETTINGS'

    doLog "DEBUG reading: the following configuration file"
    doLog "DEBUG ""$cnf_file"
    ( set -o posix ; set ) | sort >"$tmp_dir/vars.before"

    eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
        -e 's/#.*$//' \
        -e 's/[[:space:]]*$//' \
        -e 's/^[[:space:]]*//' \
        -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
        < $cnf_file \
        | sed -n -e "/^\[$ini_section\]/,/^\s*\[/{/^[^#].*\=.*/p;}"`

    ( set -o posix ; set ) | sort >"$tmp_dir/vars.after"

    doLog "INFO added the following vars from section: [$ini_section]"
    cmd="$(comm -3 $tmp_dir/vars.before $tmp_dir/vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
    echo -e "$cmd"
    echo -e "$cmd" >> $log_file
    echo -e "\n\n"
    sleep 1; printf "\033[2J";printf "\033[0;0H" # and clear the screen
}
#eof func doParseConfFile
Jordan Georgiev
quelle