Il modo migliore per leggere un file di configurazione in bash


23

Qual è il modo migliore per leggere un file di configurazione in bash?
Ad esempio, hai uno script e non sei disposto a compilare manualmente tutte le configurazioni ogni volta che chiami lo script.

Modifica 1: Penso di non averlo chiarito, quindi: quello che voglio è ... Ho un configfile che è come

variable_name value  
variable_name value ...  

e voglio leggerlo. So che potrei semplicemente accettarlo per gli argomenti che sto cercando o così ... ma forse c'è un modo più intelligente :)


2
Dovrai mostrare che tipo di configurazione intendi. Fornisci un esempio.
Muru,

Vedi anche una domanda molto simile su StackExchange di Unix e Linux.
Michael,

Risposte:


38

Come diceva mbiber, sourceun altro file. Ad esempio, il tuo file di configurazione (diciamo some.config) sarebbe:

var1=val1
var2=val2

E la tua sceneggiatura potrebbe apparire come:

#! /bin/bash

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

. /path/to/some.config

echo "$var1" "$var2"

I molti file in /etc/defaultgenere servono come file di configurazione per altri script di shell in modo simile. Un esempio molto comune dai post qui è /etc/default/grub. Questo file viene utilizzato per impostare le opzioni di configurazione per GRUB, poiché grub-mkconfigè uno script shell che lo genera:

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

Se devi veramente elaborare la configurazione del modulo:

var1 some value 1
var2 some value 2

Quindi potresti fare qualcosa del tipo:

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

(Potresti anche fare qualcosa del genere eval "$var=$value", ma è più rischioso rispetto all'approvvigionamento di uno script. Inavvertitamente potresti interromperlo più facilmente di un file di origine.)


È un ottimo modo, potrei usare lo spazio bianco sostitutivo di sed per "="
IcyIcyIce

1
@IcyIcyIce Semplicemente no. Perché non puoi scriverlo =dall'inizio?
muru

1
@IcyIcyIce Ecco come dovrebbe essere. Puoi usare il codice shell nei vari file in /etc/default- e soprattutto per un buon uso. Se il tuo utente ignaro ha accesso alla configurazione per qualcosa che funziona come root, è già una causa persa.
muru

1
@IcyIcyIce induce i tuoi insegnanti a chiarire ciò che vogliono. Una parte dell'apprendimento dello sviluppo di software consiste nel conoscere chiaramente i requisiti.
muru

1
@IcyIcyIce vedi aggiornamento.
muru

4

Ovviamente, non sono lo bashspecialista qui, ma il concetto non dovrebbe essere diverso in qualsiasi lingua tu usi:

Un esempio

Nell'esempio seguente, è possibile utilizzare uno script (molto) di base per impostare una stringa o stampare una stringa, come impostato nel file di configurazione:

#!/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

Poi

  • Per impostare una stringa nel file di configurazione:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Successivamente, per stampare la stringa, come definita nel "file di configurazione":

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

Naturalmente, in un vero script applicato, devi aggiungere molte cose per assicurarti che gli argomenti siano corretti, decidere cosa fare quando l'input è errato, il file delle impostazioni non esiste ecc., Ma:

Questa è l'idea di base


grazie, sto solo aggiornando la domanda, penso di non averlo chiarito ... ma in casi semplici questo funzionerebbe come un incantesimo ofc
IcyIcyIce

4

Utilizzare sourceo .per caricare un file.

source /path/to/file

o

. /path/to/file

Si consiglia inoltre di verificare se il file esiste prima di caricarlo perché non si desidera continuare a eseguire lo script se non è presente un file di configurazione.


0

Sto usando questo ...

#!/bin/bash

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

Il file conf viene analizzato con sed e quindi valutato come semplici assegnazioni variabili

Prima sed analisi dei valori chiave (supporta anche = circondato da spazi)

Il secondo sed rimuove gli spazi intorno a = segno per un'assegnazione variabile valida

È possibile aggiungere un ulteriore trattamento sed

Tutti gli altri testi non corrispondenti nel file conf verranno rimossi (inclusi # o; commento e altro)

Essere consapevoli del fatto che i comandi di shell a linea singola possono anche essere valutati da questo file di configurazione!


1
Uso inutile dicat . Perché invochi seddue volte back-to-back? Puoi concatenare i sedcomandi in questo modo:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster,

Inoltre, questo sedcomando genererà un output vuoto per le voci del file di configurazione di esempio nella domanda. -1
David Foerster,

1
Un altro possibile miglioramento: utilizzare il .comando e il reindirizzamento dei processi anziché le variabili temporanee per contenere l'output del processo secondario:. <(sed ... "$CFG_FILE")
David Foerster,

Ovviamente il mio esempio usa key = value come file di configurazione. È una pratica migliore del "valore chiave". Usando key = value il mio esempio funziona. Il tuo concatenamento dei comandi sed è migliore, lo ammetto, ma il comando source si aspetta un file in modo che possiamo usare:, eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")che è molto meglio per capire cosa sta succedendo.
smARTin

Sì, si .aspetta un file e la sostituzione del processo viene espansa in un file. . <(echo echo foo)funziona esattamente come previsto in Bash v4.3.11. In piccoli esempi probabilmente non importerà. Preferirei non passare più kilobyte tramite la sostituzione dei comandi.
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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.