Modification du fichier de configuration via un script bash

9

J'ai essayé d'écrire un simple script bash que j'utiliserai pour installer une application et mettre à jour son fichier de configuration. J'ai du mal à faire modifier son fichier de configuration.

# DBHost=localhost
DBName=test
# DBPassword=

des suggestions comment je peux obtenir ci-dessus modifié comme ci-dessous?

DBHost=localhost
DBName=database
DBPassword=password
compixtr
la source
Je ne peux pas croire que nous devons écrire des expressions régulières sujettes aux erreurs juste pour faire cette tâche très courante. Il devrait vraiment y avoir un outil standardisé comme "update_config test.confg -uncomment_if_pressent DBHost = localhost".
bigjosh

Réponses:

3

Le meilleur moyen dépend de si vous vous attendez à ce que le fichier soit également modifié par les humains, de la complexité du fichier et de la priorité de votre script s'il semble que quelqu'un d'autre souhaite une valeur différente. Autrement dit, si le fichier contient déjà DBPassword=swordfish, voulez-vous le conserver ou le remplacer par DBPassword=password?

Une manière courante de gérer cela est d'avoir une section du fichier délimitée par des «commentaires magiques» et de ne modifier que la partie entre ces commentaires. Voici un moyen de le faire avec awk. Si les commentaires magiques ne sont pas présents, la nouvelle section est ajoutée à la fin du fichier. Attention: code non testé.

begin_marker='# BEGIN AUTOMATICALLY EDITED PART, DO NOT EDIT'
end_marker='# END AUTOMATICALLY EDITED PART'
new_section='DBHost=localhost
DBName=database
DBPassword=password'
export begin_marker end_marker
awk <file.conf >file.conf.new -v begin_marker="$begin_marker" -v begin_marker="$end_marker" -v new_section="$new_section" '
    1 {print}
    $0 == begin_marker && !changed {
        do {getline} while ($0 != end_marker); # discard old section content
        print new_section;
        print;
        changed = 1;
    }
    END {if (!changed) {print begin_marker; print new_section; print end_marker;}}
'
ln -f file.conf file.conf.old
mv -f file.conf.new file.conf

Cette approche ne fonctionne pas bien si le programme qui lit le fichier de configuration ne prend pas en charge plusieurs lignes définissant le même élément de configuration. Dans ce cas, vous devrez vraiment supprimer les anciens. Dans ce cas, je conseillerais de laisser les commentaires intacts et d'ajouter vos propres paramètres à la fin.

grep -vE '^[[:blank:]]*(DBHost|DBName|DBPassword)=$' <file.conf >file.conf.new
cat <<EOF >>file.conf.new
DBHost=localhost
DBName=database
DBPassword=password
EOF
ln -f file.conf file.conf.old
mv -f file.conf.new file.conf
Gilles 'SO- arrête d'être méchant'
la source
Avez-vous testé ce code? ou n'est-il toujours pas testé?
rubo77
Autres excellents exemples ici: stackoverflow.com/questions/5955548/…
rubo77
2

Si c'est tout ce dont vous avez besoin, vous pouvez faire quelque chose comme

sed  -i.bak -e 's/DBName=.*/DBName=database/' \
 -e 's/#* *DBHost=.*/DBHost=localhost/' \
 -e 's/#* *DBPassword=.*/DBPassword=password/' config.file

Cette copie de l'original config.filepour config.file.baket apporter les changements nécessaires.

terdon
la source
2

Je vais aller avec "ex" en mode silencieux:

ex -s $CONFIG_FILE << END_CMDS
%s/^#.DBHost/DBHOST/
%s/DBName=test/DBName=database/
%s/^#.DBPassword/DBPassword/
w!
q
END_CMDS

La sedcommande de terdon est compacte et efficace. Mais l'interaction d'un "document ici" plein de commandes ex et d'interpolation de chaîne shell peut être puissante. Par exemple, le mot de passe peut être remplacé par la valeur d'une variable shell:

%s/^#.DBPassword=password/DBPassword=$PASSWORD/

Si vous utilisez viou vimet que vous connaissez le mode ':', l'ajout de nouvelles / meilleures / différentes modifications est également assez facile.

Bruce Ediger
la source
Bien que ex soit puissant, il est difficile de se remettre d'erreurs (par exemple lorsqu'une ligne attendue est manquante). Ici, vous pouvez vous échapper sans aucun comportement conditionnel, mais cela ne se généralise pas si bien.
Gilles 'SO- arrête d'être méchant'