Meilleure façon de lire un fichier de configuration en bash

23

Quelle est la meilleure façon de lire un fichier de configuration dans bash?
Par exemple, vous avez un script et vous ne souhaitez pas remplir manuellement toutes les configurations chaque fois que vous appelez le script.

Edit 1: Je pense que je n'ai pas été clair, donc: ce que je veux c'est ... J'ai un fichier de configuration qui est comme

variable_name value  
variable_name value ...  

et je veux lire ça. Je sais que je pourrais simplement le chercher pour les arguments que je recherche ou alors ... mais peut-être qu'il y a un moyen plus intelligent :)

IcyIcyIce
la source
2
Vous devrez montrer de quel type de configuration vous parlez. Donnez un exemple.
muru
Voir aussi une question très similaire sur StackExchange Unix et Linux.
Michael

Réponses:

38

Comme l'a dit mbiber, sourceun autre fichier. Par exemple, votre fichier de configuration (disons some.config) serait:

var1=val1
var2=val2

Et votre script pourrait ressembler à:

#! /bin/bash

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

. /path/to/some.config

echo "$var1" "$var2"

Les nombreux fichiers dans /etc/defaultservent généralement de fichiers de configuration pour d'autres scripts shell de la même manière. Un exemple très courant des publications ici est /etc/default/grub. Ce fichier est utilisé pour définir les options de configuration de GRUB, car il grub-mkconfigs'agit d'un script shell qui le source:

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

Si vous devez vraiment traiter la configuration du formulaire:

var1 some value 1
var2 some value 2

Ensuite, vous pourriez faire quelque chose comme:

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

(Vous pouvez également faire quelque chose comme eval "$var=$value", mais c'est plus risqué que de sourcer un script. Vous pouvez par inadvertance le casser plus facilement qu'un fichier source.)

muru
la source
C'est un excellent moyen, je pourrais utiliser un espace de remplacement sed pour "="
IcyIcyIce
1
@IcyIcyIce Tout simplement pas. Pourquoi ne pouvez-vous pas l'écrire =depuis le début?
muru
1
@IcyIcyIce Voilà comment c'est censé être. Vous pouvez utiliser le code shell dans les différents fichiers dans /etc/default- et surtout à bon escient. Si votre utilisateur désemparé a accès à la configuration de quelque chose qui s'exécute en tant que root, c'est déjà une cause perdue.
muru
1
@IcyIcyIce demandez à vos professeurs de clarifier ce qu'ils veulent. Une partie de l'apprentissage du développement de logiciels consiste à connaître clairement les exigences.
muru
1
@IcyIcyIce voir la mise à jour.
muru
4

Évidemment, je ne suis pas le bashspécialiste ici, mais le concept ne devrait pas être différent dans la langue que vous utilisez:

Un exemple

Dans l'exemple ci-dessous, vous pouvez utiliser un script (très) basique pour définir une chaîne ou imprimer une chaîne, comme défini dans votre fichier de configuration:

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

ensuite

  • Pour définir une chaîne dans votre fichier de configuration:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Par la suite, pour imprimer la chaîne, telle que définie dans votre "fichier de configuration":

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

Bien sûr, dans un vrai script appliqué, vous devez ajouter beaucoup de choses pour vous assurer que les arguments sont corrects, décider quoi faire lorsque la saisie est incorrecte, le fichier de paramètres n'existe pas, etc., mais:

Telle est l'idée de base

Jacob Vlijm
la source
merci, je suis juste en train de mettre à jour la question, je pense que je n'ai pas été claire ... mais dans des cas simples, cela fonctionnerait comme un charme ofc
IcyIcyIce
4

Utilisez sourceou .pour charger dans un fichier.

source /path/to/file

ou

. /path/to/file

Il est également recommandé de vérifier si le fichier existe avant de le charger car vous ne souhaitez pas continuer à exécuter votre script si aucun fichier de configuration n'est présent.

mbiber
la source
0

J'utilise celui-ci ...

#!/bin/bash

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

Le fichier de configuration est analysé avec sed puis évalué comme de simples affectations de variables

Premier sed analysant les valeurs clés (prend également en charge = entouré d'espaces)

Le deuxième sed supprime les espaces autour de = signe pour une affectation de variable valide

Un traitement sed supplémentaire peut être ajouté

Tout autre texte ne correspondant pas dans le fichier conf sera supprimé (y compris # ou; commentaire et autres)

Sachez que les commandes shell sur une seule ligne peuvent également être évaluées à partir de ce fichier de configuration!

smARTin
la source
1
Utilisation inutile decat . Pourquoi invoquez-vous seddeux fois de suite? Vous pouvez enchaîner des sedcommandes comme ceci:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster
De plus, cette sedcommande générera une sortie vide pour les exemples d'entrées de fichier de configuration dans la question. -1
David Foerster
1
Autre amélioration possible: utilisez la .commande et la redirection de processus au lieu de variables temporaires pour conserver la sortie du sous-processus:. <(sed ... "$CFG_FILE")
David Foerster
Bien sûr, mon exemple utilise key = value comme un fichier de configuration. C'est une meilleure pratique que la «valeur clé». En utilisant key = value, mon exemple fonctionne. Votre chaînage des commandes sed est meilleur, je l'admets, mais la commande source attend le fichier pour que nous puissions utiliser:, eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")ce qui est beaucoup mieux pour comprendre ce qui se passe.
smARTin
Oui, .attend un fichier et la substitution de processus est étendue à un fichier. . <(echo echo foo)fonctionne exactement comme prévu dans Bash v4.3.11. Dans de petits exemples, cela n'aura probablement pas d'importance. Je préfère cependant ne pas passer plusieurs kilo-octets par substitution de commande.
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
Yordan Georgiev
la source