137 votes

Comment saisir une valeur INI dans un script shell script ?

J'ai un fichier parameters.ini, tel que :

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Je veux lire et utiliser la version de la base de données spécifiée dans le fichier parameters.ini à partir d'un shell bash script pour pouvoir la traiter.

#!/bin/sh    
# Need to get database version from parameters.ini file to use in script    
php app/console doctrine:migrations:migrate $DATABASE_VERSION

Comment dois-je m'y prendre ?

6 votes

Est-ce que l'une de ces réponses respecte les sections ?

0 votes

Notez que tout script qui commence par #!/bin/sh est un script POSIX sh, et non un script bash. C'est une distinction importante, car sh ne dispose pas de fonctionnalités comme les tableaux et les cartes (que bash appelle "tableaux associatifs") qui sont très utiles pour construire ce genre de choses.

102voto

Ali Lown Points 967

Pourquoi ne pas rechercher cette ligne en utilisant awk ?

version=$(awk -F "=" '/database_version/ {print $2}' parameters.ini)

8 votes

Cela inclut les espaces après '='.

15 votes

Pour couper les espaces, ajoutez | tr -d ' ' à la fin.

32 votes

Ce n'est pas vraiment une bonne solution. Pensez à avoir 2 sections [parameters.ini] avec chacune une variable ' database_version'. Vous obtenez alors la valeur deux fois.

84voto

kenorb Points 2464

Vous pouvez utiliser le parseur natif de bash pour interpréter les valeurs ini, par :

$ source <(grep = file.ini)

Un exemple de fichier :

[section-a]
  var1=value1
  var2=value2
  IPS=( "1.2.3.4" "1.2.3.5" )

Pour accéder aux variables, il suffit de les imprimer : echo $var1 . Vous pouvez également utiliser des tableaux comme indiqué ci-dessus ( echo ${IPS[@]} ).

Si vous ne voulez qu'une seule valeur, il suffit de la rechercher par grep :

source <(grep var1 file.ini)

Pour la démo, voir cet enregistrement sur asciinema .

Elle est simple car vous n'avez pas besoin d'une bibliothèque externe pour analyser les données, mais elle présente quelques inconvénients. Par exemple :

  • Si vous avez des espaces entre = (nom et valeur de la variable), alors vous devez d'abord couper les espaces, par ex.

      $ source <(grep = file.ini | sed 's/ *= */=/g')

    Ou si vous ne vous souciez pas des espaces (y compris au milieu), utilisez :

      $ source <(grep = file.ini | tr -d ' ')
  • Pour soutenir ; remplacez-les par # :

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
  • Les sections ne sont pas prises en charge (par exemple si vous avez [section-name] alors vous devez le filtrer comme indiqué ci-dessus, par exemple. grep = ), de même pour les autres erreurs inattendues.

    Si vous devez lire une valeur spécifique dans une section spécifique, utilisez la fonction grep -A , sed , awk o ex ).

    Par exemple

      source <(grep = <(grep -A5 '\[section-b\]' file.ini))

    Note : Lorsque -A5 est le nombre de lignes à lire dans la section. Remplacer source con cat pour déboguer.

  • Si vous avez des erreurs d'analyse, ignorez-les en ajoutant : 2>/dev/null

Voir aussi :

57voto

egridasov Points 81

Sed one-liner, qui prend en compte les sections. Fichier d'exemple :

[section1]
param1=123
param2=345
param3=678

[section2]
param1=abc
param2=def
param3=ghi

[section3]
param1=000
param2=111
param3=222

Disons que vous voulez le paramètre 2 de la section 2. Exécutez ce qui suit :

sed -nr "/^\[section2\]/ { :l /^param2[ ]*=/ { s/[^=]*=[ ]*//; p; q;}; n; b l;}" ./file.ini

vous donnera

def

4 votes

Sed -nr "/^\[SECTION2]/ { :l /^ \s *[^#].*/ p ; n ; /^\[/ q ; b l ; }" file.conf # pour obtenir la section entière sans commentaires pour un fichier de style .conf avec [SECTION2] et # des lignes de commentaires de style hash. Puis grep pour paramname si vous voulez juste un paramètre.

1 votes

Il vaut mieux utiliser les adresses de la gamme sed que de lire les lignes suivantes : "/^\[section2\]/,/^\[/{...}"

4 votes

Si vous êtes sur un Mac : brew install gnu-sed et ensuite utiliser gsed (autrement : sed: illegal option -- r )

36voto

Fredrik Pihl Points 20944

Bash ne fournit pas d'analyseur syntaxique pour ces fichiers. Évidemment, vous pouvez utiliser une commande awk ou quelques appels sed, mais si vous êtes un prêtre bash et que vous ne voulez pas utiliser un autre shell, alors vous pouvez essayer le code obscur suivant :

#!/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 after =
    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
}

cfg_writer ()
{
    IFS=' '$'\n'
    fun="$(declare -F)"
    fun="${fun//declare -f/}"
    for f in $fun; do
        [ "${f#cfg.section}" == "${f}" ] && continue
        item="$(declare -f ${f})"
        item="${item##*\{}"
        item="${item%\}}"
        item="${item//=*;/}"
        vars="${item//=*/}"
        eval $f
        echo "[${f#cfg.section.}]"
        for var in $vars; do
            echo $var=\"${!var}\"
        done
    done
}

Utilisation :

# parse the config file called 'myfile.ini', with the following
# contents::
#   [sec2]
#   var2='something'
cfg.parser 'myfile.ini'

# enable section called 'sec2' (in the file [sec2]) for reading
cfg.section.sec2

# read the content of the variable called 'var2' (in the file
# var2=XXX). If your var2 is an array, then you can use
# ${var[index]}
echo "$var2"

L'analyseur d'ini de Bash se trouve à l'adresse suivante Le site du blog Old School DevOps .

4 votes

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien à titre de référence. Les réponses ne comportant qu'un lien peuvent devenir invalides si la page liée change.

10 votes

C'est normalement moi qui donne des commentaires de ce genre ; tout ce que je peux dire, c'est que j'étais jeune et stupide :-)

2 votes

Si vous aimez cet extrait, il y a une amélioration sur github.com/albfan/bash-ini-parser

24voto

Gustavo González Points 251

Il suffit d'inclure votre fichier .ini dans le corps de bash :

Fichier exemple.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

Fichier exemple.sh

#!/bin/bash
#Including .ini file
. example.ini
#Test
echo "${DBNAME}   ${DBUSER}  ${DBPASSWORD}"

3 votes

Ce devrait être la réponse choisie. Elle fonctionne avec file.properties et est tolérante aux pannes (fichier avec ligne vide à l'intérieur). Merci

29 votes

Ne gère pas la partie [section] des fichiers INI.

0 votes

C'est la meilleure réponse !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X