Comment récupérer une valeur INI dans un script shell?

97

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

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Je souhaite lire et utiliser la version de la base de données spécifiée dans le fichier parameters.ini à partir d'un script shell bash afin de 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 ferais-je ça?

Stephen Watkins
la source
2
L'une de ces réponses respecte-t-elle du tout les sections?
ManuelSchneid3r

Réponses:

83

Que diriez-vous de grepping pour cette ligne puis d'utiliser awk

version=$(awk -F "=" '/database_version/ {print $2}' parameters.ini)
Ali Lown
la source
6
Cela inclura des espaces après «=».
10
Pour couper les espaces, ajoutez | tr -d ' 'à la fin.
kenorb
22
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.
nerdoc
4
oui s'il vous plaît envisager un analyseur ini spécialisé comme crudini, car il existe de nombreux cas de bord non traités par ce qui précède
pixelbeat
3
Toujours utile et plus rapide pour les fichiers ini de base.
Cyril N.21
51

Vous pouvez utiliser l'analyseur natif bash pour interpréter les valeurs ini, en:

$ source <(grep = file.ini)

Exemple de fichier:

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

Pour les variables d' accès, il vous 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 juste grep pour cela:

source <(grep var1 file.ini)

Pour la démo, vérifiez cet enregistrement à asciinema .

C'est simple car vous n'avez besoin d'aucune bibliothèque externe pour analyser les données, mais cela présente certains inconvénients. Par exemple:

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

      $ 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 les ;commentaires, 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 d'autres erreurs inattendues.

    Si vous avez besoin de lire une valeur spécifique prévue à l' article spécifique, l' utilisation grep -A, sed, awkou ex).

    Par exemple

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

    Remarque: Où -A5est le nombre de lignes à lire dans la section. Remplacez sourcepar catpour déboguer.

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

Voir également:

Kenorb
la source
1
mais ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))cela ne fonctionnera pas pour cela: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. où il n'y a pas de règle définie avec des lignes
Psychozoic
J'ai essayé d'utiliser source, mais quand je fais écho à $ var1, il ne renvoie rien. Pourquoi?
A. Gh
@ A.Gh je ne suis pas sûr, ça marche pour moi. Assurez-vous que vous utilisez le shell Bash. Voir: asciinema.org/a/306481
kenorb
Cela aurait été élégant, mais n'a pas réussi à le faire fonctionner sous OS X (Catalina). Cela fonctionne à partir de l'invite de commande dans zsh (shell par défaut actuel), mais une fois que je l'ai mis dans un script, j'obtiens l'erreur syntax error near unexpected token '('. Avec bash, il échoue silencieusement à la fois à partir de l'invite et du script.
MiRin
29

Bash ne fournit pas d'analyseur pour ces fichiers. Évidemment, vous pouvez utiliser une commande awk ou quelques appels sed, mais si vous êtes bash-prêtre et que vous ne voulez pas utiliser d'autre shell, 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
}

Usage:

# 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"

Bash ini-parser peut être trouvé sur le site de blog The Old School DevOps .

Fredrik Pihl
la source
3
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 pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change.
alecxe
8
C'est normalement moi qui donne des commentaires comme celui-ci; tout ce que je peux dire, c'est que j'étais jeune et stupide :-)
Fredrik Pihl
1
Si vous aimez cet extrait, il y a une amélioration sur github.com/albfan/bash-ini-parser
albfan
3
Pour fonctionner correctement, vous devez utiliser cfg_parser au lieu de cfg.parser
Wes
1
TYPO: "cfg.parser" doit être "cfg_parser".
Setop
26

Sed one-liner, qui tient compte des sections. Exemple de fichier:

[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 param2 de la section2. Exécutez ce qui suit:

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

te donnera

def
Egridasov
la source
3
sed -nr "/ ^ \ [SECTION2 \] / {: l /^\s*[^# </font>.*/ p; n; / ^ \ [/ q; bl;}" file.conf # pour obtenir la section entière sans commentaires pour un fichier de style .conf avec [SECTION2] et # lignes de commentaires de style haché. Puis grep pour paramname si vous ne voulez qu'un seul paramètre.
gaoithe
mieux utiliser les adresses de plage sed que de lire les lignes suivantes:"/^\[section2\]/,/^\[/{...}"
bassin
1
si sur un Mac: brew install gnu-sedpuis utilisez gsed(autrement: sed: illegal option -- r)
frnhr
Quelqu'un peut-il expliquer comment fonctionne l' sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" expression? merci
foo_l
22

Incluez simplement votre fichier .ini dans le corps de bash:

Fichier example.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

Fichier example.sh

#!/bin/bash
#Including .ini file
. example.ini
#Test
echo "${DBNAME}   ${DBUSER}  ${DBPASSWORD}"
Gustavo González
la source
2
Cela devrait être la réponse choisie. Il fonctionne avec file.properties et est tolérant aux pannes (fichier avec une ligne vide à l'intérieur). Merci
Anthony
17
ne gère pas la partie [section] des fichiers INI.
Setop
C'est la meilleure réponse!
JavaSheriff
17
Espérons que personne n'ajoute jamais un "rm -rf /" au fichier ini :(
HeyMan
1
Beaucoup plus sûr dans le sous-shell: $ (. Example.ini; echo $ DBNAME)
Rich Remer
14

Toutes les solutions que j'ai vues jusqu'à présent ont également touché des lignes commentées. Celui-ci ne l'a pas fait, si le code du commentaire est ;:

awk -F '=' '{if (! ($0 ~ /^;/) && $0 ~ /database_version/) print $2}' file.ini
Opux
la source
2
Cela devrait être la réponse acceptée car a) Il gère les lignes commentées b) simple :)
Sudar
1
C'est génial, ty @PenguinLust! Utilisation: 1. Commentaires sur toute la ligne autorisés avec un préfixe point-virgule (aucun commentaire de fin de ligne en ligne n'est autorisé); L'espace blanc n'est pas élidé du résultat (donc si le fichier ini a 'a = 1', alors la recherche du script pour 'a' est évaluée à '1').
AnneTheAgile
1
Pour couper les espaces, ajoutez | tr -d ' 'à la fin.
kenorb
Cela pose le même problème que la réponse suggérée; il recherche chaque instance de "database_version"
Nubcake
12

une ou plusieurs solutions possibles

dbver=$(sed -n 's/.*database_version *= *\([^ ]*.*\)/\1/p' < parameters.ini)
echo $dbver
jm666
la source
8

Afficher la valeur de my_key dans un style ini mon_fichier :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - ne rien imprimer par défaut
  • -e - exécuter l'expression
  • s/PATTERN//p - affichez tout ce qui suit ce modèle dans le modèle:
  • ^ - le motif commence au début de la ligne
  • \s - caractère d'espacement
  • * - zéro ou plusieurs (caractères d'espacement)

Exemple:

$ cat my_file
# Example INI file
something   = foo
my_key      = bar
not_my_key  = baz
my_key_2    = bing

$ sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
bar

Alors:

Trouvez un modèle où la ligne commence par zéro ou plusieurs espaces blancs, suivi de la chaîne my_key , suivi de zéro ou plusieurs espaces blancs, d'un signe égal, puis de zéro ou plusieurs espaces blancs à nouveau. Affichez le reste du contenu sur cette ligne en suivant ce modèle.

Dean plutôt
la source
Votre exemple ne fonctionne pas (non barimprimé), du moins sous Unix / OSX.
kenorb
7

sed

Vous pouvez utiliser sedpour analyser le fichier de configuration ini, en particulier lorsque vous avez des noms de section comme:

# last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.

[database]
# use IP address in case network name resolution is not working
server=192.0.2.62
port=143
file=payroll.dat

vous pouvez donc utiliser le sedscript suivant pour analyser les données ci-dessus:

# Configuration bindings found outside any section are given to
# to the default section.
1 {
  x
  s/^/default/
  x
}

# Lines starting with a #-character are comments.
/#/n

# Sections are unpacked and stored in the hold space.
/\[/ {
  s/\[\(.*\)\]/\1/
  x
  b
}

# Bindings are unpacked and decorated with the section
# they belong to, before being printed.
/=/ {
  s/^[[:space:]]*//
  s/[[:space:]]*=[[:space:]]*/|/
  G
  s/\(.*\)\n\(.*\)/\2|\1/
  p
}

cela convertira les données ini dans ce format plat:

owner|name|John Doe
owner|organization|Acme Widgets Inc.
database|server|192.0.2.62
database|port|143
database|file|payroll.dat

il sera donc plus facile d'analyser en utilisant sed, awkou readen ayant des noms de section dans chaque ligne.

Crédits & source: Fichiers de configuration pour les scripts shell , Michael Grünewald


Vous pouvez également utiliser ce projet chilladx/config-parser:, un analyseur de configuration utilisant sed.

Kenorb
la source
C'est bien! Je pensais l'aplatir comme ça, mais c'est des kilomètres au-delà de ce que j'allais pirater ensemble!
grinch
6

Vous pouvez utiliser l' crudinioutil pour obtenir des valeurs ini, par exemple:

DATABASE_VERSION=$(crudini --get parameters.ini '' database_version)
pixelbeat
la source
Notez qu'il est basé sur Python, donc peut ne pas convenir aux applications Linux embarquées par exemple.
Craig McQueen
Cela fait partie des dépôts standard de Fedora (testés avec 31). yum install crudini
shrewmouse
5

Pour les personnes (comme moi) qui cherchent à lire des fichiers INI à partir de scripts shell (lire le shell, pas bash) - j'ai lancé la petite bibliothèque d'aide qui essaie de faire exactement cela:

https://github.com/wallyhall/shini (licence MIT, faites-en ce que vous voulez. J'ai lié ci-dessus en l'incluant en ligne car le code est assez long.)

C'est un peu plus "compliqué" que les simples sedlignes suggérées ci-dessus - mais fonctionne sur une base très similaire.

La fonction lit un fichier ligne par ligne - à la recherche de marqueurs de section ( [section]) et de déclarations clé / valeur ( key=value).

En fin de compte, vous obtenez un rappel de votre propre fonction - section, clé et valeur.

wally
la source
@CraigMcQueen - J'ai ajouté ce soir un support d'écriture de très qualité alpha. Ce n'est pas "complet" par aucun effort d'imagination!
wally
Brillant! :-) Major
Jonathan
5

Similaire aux autres réponses Python, vous pouvez le faire en utilisant l' -cindicateur pour exécuter une séquence d'instructions Python données sur la ligne de commande:

$ python3 -c "import configparser; c = configparser.ConfigParser(); c.read('parameters.ini'); print(c['parameters.ini']['database_version'])"
20110611142248

Cela a l'avantage de ne nécessiter que la bibliothèque standard Python et l'avantage de ne pas écrire un fichier de script séparé.

Ou utilisez un document ici pour une meilleure lisibilité, ainsi:

#!/bin/bash
python << EOI
import configparser
c = configparser.ConfigParser()
c.read('params.txt')
print c['chassis']['serialNumber']
EOI

serialNumber=$(python << EOI
import configparser
c = configparser.ConfigParser()
c.read('params.txt')
print c['chassis']['serialNumber']
EOI
)

echo $serialNumber
argentpepper
la source
Que faire si je veux récupérer une section entière en tant que tableau à l'aide de cette commande?
Debopam Parua
2

Certaines réponses ne respectent pas les commentaires. Certains ne respectent pas les sections. Certains ne reconnaissent qu'une seule syntaxe (seulement ":" ou seulement "="). Certaines réponses Python échouent sur ma machine en raison d'une captialisation différente ou de l'échec de l'importation du module sys. Tous sont un peu trop laconiques pour moi.

J'ai donc écrit le mien, et si vous avez un Python moderne, vous pouvez probablement l'appeler depuis votre shell Bash. Il a l'avantage d'adhérer à certaines des conventions de codage Python courantes et fournit même des messages d'erreur et une aide judicieux. Pour l'utiliser, nommez-le quelque chose comme myconfig.py (ne l'appelez PAS configparser.py ou il peut essayer de s'importer,) rendez-le exécutable et appelez-le comme

value=$(myconfig.py something.ini sectionname value)

Voici mon code pour Python 3.5 sur Linux:

#!/usr/bin/env python3
# Last Modified: Thu Aug  3 13:58:50 PDT 2017
"""A program that Bash can call to parse an .ini file"""

import sys
import configparser
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="A program that Bash can call to parse an .ini file")
    parser.add_argument("inifile", help="name of the .ini file")
    parser.add_argument("section", help="name of the section in the .ini file")
    parser.add_argument("itemname", help="name of the desired value")
    args = parser.parse_args()

    config = configparser.ConfigParser()
    config.read(args.inifile)
    print(config.get(args.section, args.itemname))
4dummies
la source
2

simplicité complexe

fichier ini

test.ini

[section1]
name1=value1
name2=value2
[section2]
name1=value_1
  name2  =  value_2

script bash avec lecture et exécution

/ bin / parseini

#!/bin/bash

set +a
while read p; do
  reSec='^\[(.*)\]$'
  #reNV='[ ]*([^ ]*)+[ ]*=(.*)'     #Remove only spaces around name
  reNV='[ ]*([^ ]*)+[ ]*=[ ]*(.*)'  #Remove spaces around name and spaces before value
  if [[ $p =~ $reSec ]]; then
      section=${BASH_REMATCH[1]}
  elif [[ $p =~ $reNV ]]; then
    sNm=${section}_${BASH_REMATCH[1]}
    sVa=${BASH_REMATCH[2]}
    set -a
    eval "$(echo "$sNm"=\""$sVa"\")"
    set +a
  fi
done < $1

puis dans un autre script, je source les résultats de la commande et je peux utiliser toutes les variables dans

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

enfin depuis la ligne de commande la sortie est donc

# ./test.sh 
value_2
Le codeur paresseux
la source
Excellente solution! Merci!
Michael
2

Voici ma version, qui analyse les sections et en remplit un tableau associatif global g_iniProperties . Notez que cela ne fonctionne qu'avec bash v4.2 et supérieur.

function parseIniFile() { #accepts the name of the file to parse as argument ($1)
    #declare syntax below (-gA) only works with bash 4.2 and higher
    unset g_iniProperties
    declare -gA g_iniProperties
    currentSection=""
    while read -r line
    do
        if [[ $line = [*  ]] ; then
            if [[ $line = [* ]] ; then 
                currentSection=$(echo $line | sed -e 's/\r//g' | tr -d "[]")  
            fi
        else
            if [[ $line = *=*  ]] ; then
                cleanLine=$(echo $line | sed -e 's/\r//g')
                key=$currentSection.$(echo $cleanLine | awk -F: '{ st = index($0,"=");print  substr($0,0,st-1)}')
                value=$(echo $cleanLine | awk -F: '{ st = index($0,"=");print  substr($0,st+1)}')
                g_iniProperties[$key]=$value
            fi
        fi;
    done < $1
}

Et voici un exemple de code utilisant la fonction ci-dessus:

parseIniFile "/path/to/myFile.ini"
for key in "${!g_iniProperties[@]}"; do
    echo "Found key/value $key = ${g_iniProperties[$key]}"
done
Karen Gabrielyan
la source
1

Ce script obtiendra les paramètres comme suit:

ce qui signifie que si votre ini a:

pars_ini.ksh <chemin vers le fichier ini> <nom du secteur dans le fichier Ini> <le nom dans le nom = valeur à renvoyer>

par exemple. comment l'appeler:


[environnement]

a = x

[DataBase_Sector]

DSN = quelque chose


Puis appelant:

pars_ini.ksh /users/bubu_user/parameters.ini DataBase_Sector DSN

cela récupérera le "quelque chose" suivant

le script "pars_ini.ksh":

\#!/bin/ksh

\#INI_FILE=path/to/file.ini

\#INI_SECTION=TheSection

\# BEGIN parse-ini-file.sh

\# SET UP THE MINIMUM VARS FIRST

alias sed=/usr/local/bin/sed

INI_FILE=$1

INI_SECTION=$2

INI_NAME=$3

INI_VALUE=""


eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \

    -e 's/;.*$//' \

    -e 's/[[:space:]]*$//' \

    -e 's/^[[:space:]]*//' \

    -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \

   < $INI_FILE  \

    | sed -n -e "/^\[$INI_SECTION\]/,/^\s*\[/{/^[^;].*\=.*/p;}"`


TEMP_VALUE=`echo "$"$INI_NAME`

echo `eval echo $TEMP_VALUE`
jeo
la source
1

J'ai écrit un script python rapide et facile à inclure dans mon script bash.

Par exemple, votre fichier ini est appelé food.ini et dans le fichier, vous pouvez avoir des sections et des lignes:

[FRUIT]
Oranges = 14
Apples = 6

Copiez ce petit script Python de 6 lignes et enregistrez-le sous configparser.py

#!/usr/bin/python
import configparser
import sys
config = configparser.ConfigParser()
config.read(sys.argv[1])
print config.get(sys.argv[2],sys.argv[3])

Maintenant, dans votre script bash, vous pouvez le faire par exemple.

OrangeQty=$(python configparser.py food.ini FRUIT Oranges)

ou

ApplesQty=$(python configparser.py food.ini FRUIT Apples)
echo $ApplesQty

Cela suppose:

  1. vous avez installé Python
  2. vous avez installé la bibliothèque configparser (cela devrait venir avec une installation std python)

J'espère que ça aide : ¬)

joe_evans
la source
Je cherchais quelque chose qui faisait exactement cela, alors j'ai suivi l'exemple et cela fonctionne très bien. J'ai oublié que j'avais écrit ça !!!! J'ai essayé de voter pour moi mais, hélas, je ne peux pas voter pour moi !!! ha ha
joe_evans
0

Ma version du one-liner

#!/bin/bash
#Reader for MS Windows 3.1 Ini-files
#Usage: inireader.sh

# e.g.: inireader.sh win.ini ERRORS DISABLE
# would return value "no" from the section of win.ini
#[ERRORS]
#DISABLE=no
INIFILE=$1
SECTION=$2
ITEM=$3
cat $INIFILE | sed -n /^\[$SECTION\]/,/^\[.*\]/p | grep "^[:space:]*$ITEM[:space:]*=" | sed s/.*=[:space:]*//
Valentin Heinitz
la source
0

Je viens de finir d'écrire mon propre analyseur. J'ai essayé d'utiliser divers analyseurs trouvés ici, aucun ne semble fonctionner à la fois avec ksh93 (AIX) et bash (Linux).

C'est un vieux style de programmation - l'analyse ligne par ligne. Assez rapide car il utilisait peu de commandes externes. Un peu plus lent à cause de toutes les évaluations requises pour le nom dynamique du tableau.

L'ini prend en charge 3 syntaxes spéciales:

  • includeefile = fichier ini -> Charge un fichier ini supplémentaire. Utile pour diviser ini en plusieurs fichiers ou réutiliser une partie de la configuration
  • includedir = directory -> Identique à includeefile, mais inclut un répertoire complet
  • includesection = section -> Copie une section existante dans la section actuelle.

J'ai utilisé toute cette syntaxe pour avoir un fichier ini assez complexe et réutilisable. Utile pour installer des produits lors de l'installation d'un nouveau système d'exploitation - nous le faisons souvent.

Les valeurs sont accessibles avec $ {ini [$ section. $ Item]}. Le tableau DOIT être défini avant de l'appeler.

S'amuser. J'espère que c'est utile pour quelqu'un d'autre!

function Show_Debug {
    [[ $DEBUG = YES ]] && echo "DEBUG $@"
    }

function Fatal {
    echo "$@. Script aborted"
    exit 2
    }
#-------------------------------------------------------------------------------
# This function load an ini file in the array "ini"
# The "ini" array must be defined in the calling program (typeset -A ini)
#
# It could be any array name, the default array name is "ini".
#
# There is heavy usage of "eval" since ksh and bash do not support
# reference variable. The name of the ini is passed as variable, and must
# be "eval" at run-time to work. Very specific syntax was used and must be
# understood before making any modifications.
#
# It complexify greatly the program, but add flexibility.
#-------------------------------------------------------------------------------

function Load_Ini {
    Show_Debug "$0($@)"
    typeset ini_file="$1"
# Name of the array to fill. By default, it's "ini"
    typeset ini_array_name="${2:-ini}"
    typeset section variable value line my_section file subsection value_array include_directory all_index index sections pre_parse
    typeset LF="
"
    if [[ ! -s $ini_file ]]; then
        Fatal "The ini file is empty or absent in $0 [$ini_file]"
    fi

    include_directory=$(dirname $ini_file)
    include_directory=${include_directory:-$(pwd)}

    Show_Debug "include_directory=$include_directory"

    section=""
# Since this code support both bash and ksh93, you cannot use
# the syntax "echo xyz|while read line". bash doesn't work like
# that.
# It forces the use of "<<<", introduced in bash and ksh93.

    Show_Debug "Reading file $ini_file and putting the results in array $ini_array_name"
    pre_parse="$(sed 's/^ *//g;s/#.*//g;s/ *$//g' <$ini_file | egrep -v '^$')"
    while read line; do
        if [[ ${line:0:1} = "[" ]]; then # Is the line starting with "["?
# Replace [section_name] to section_name by removing the first and last character
            section="${line:1}"
            section="${section%\]}"
            eval "sections=\${$ini_array_name[sections_list]}"
            sections="$sections${sections:+ }$section"
            eval "$ini_array_name[sections_list]=\"$sections\""
            Show_Debug "$ini_array_name[sections_list]=\"$sections\""
            eval "$ini_array_name[$section.exist]=YES"
            Show_Debug "$ini_array_name[$section.exist]='YES'"
        else
            variable=${line%%=*}   # content before the =
            value=${line#*=}       # content after the =

            if [[ $variable = includefile ]]; then
# Include a single file
                Load_Ini "$include_directory/$value" "$ini_array_name"
                continue
            elif [[ $variable = includedir ]]; then
# Include a directory
# If the value doesn't start with a /, add the calculated include_directory
                if [[ $value != /* ]]; then
                    value="$include_directory/$value"
                fi
# go thru each file
                for file in $(ls $value/*.ini 2>/dev/null); do
                    if [[ $file != *.ini ]]; then continue; fi
# Load a single file
                    Load_Ini "$file" "$ini_array_name"
                done
                continue
            elif [[ $variable = includesection ]]; then
# Copy an existing section into the current section
                eval "all_index=\"\${!$ini_array_name[@]}\""
# It's not necessarily fast. Need to go thru all the array
                for index in $all_index; do
# Only if it is the requested section
                    if [[ $index = $value.* ]]; then
# Evaluate the subsection [section.subsection] --> subsection
                        subsection=${index#*.}
# Get the current value (source section)
                        eval "value_array=\"\${$ini_array_name[$index]}\""
# Assign the value to the current section
# The $value_array must be resolved on the second pass of the eval, so make sure the
# first pass doesn't resolve it (\$value_array instead of $value_array).
# It must be evaluated on the second pass in case there is special character like $1,
# or ' or " in it (code).
                        eval "$ini_array_name[$section.$subsection]=\"\$value_array\""
                        Show_Debug "$ini_array_name[$section.$subsection]=\"$value_array\""
                    fi
                done
            fi

# Add the value to the array
            eval "current_value=\"\${$ini_array_name[$section.$variable]}\""
# If there's already something for this field, add it with the current
# content separated by a LF (line_feed)
            new_value="$current_value${current_value:+$LF}$value"
# Assign the content
# The $new_value must be resolved on the second pass of the eval, so make sure the
# first pass doesn't resolve it (\$new_value instead of $new_value).
# It must be evaluated on the second pass in case there is special character like $1,
# or ' or " in it (code).
            eval "$ini_array_name[$section.$variable]=\"\$new_value\""
            Show_Debug "$ini_array_name[$section.$variable]=\"$new_value\""
        fi
    done  <<< "$pre_parse"
    Show_Debug "exit $0($@)\n"
    }
user3637822
la source
0

Cette implémentation utilise awket présente les avantages suivants:

  1. Ne renverra que la première entrée correspondante
  2. Ignore les lignes commençant par un ;
  3. Coupe les espaces de début et de fin, mais pas les espaces internes

Version formatée :

awk -F '=' '/^\s*database_version\s*=/ {
            sub(/^ +/, "", $2);
            sub(/ +$/, "", $2);
            print $2;
            exit;
          }' parameters.ini

Une doublure :

awk -F '=' '/^\s*database_version\s*=/ { sub(/^ +/, "", $2); sub(/ +$/, "", $2); print $2; exit; }' parameters.ini
Andrew Newdigate
la source
0

Lorsque j'utilise un mot de passe en base64, je mets le séparateur ":" car la chaîne base64 peut avoir "=". Par exemple (j'utilise ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

En parameters.inimettre la ligne pass:QWJjMTIzCg==, et enfin:

> PASS=`awk -F":" '/pass/ {print $2 }' parameters.ini | base64 --decode`
> echo "$PASS"
Abc123

Si la ligne a des espaces comme "pass : QWJjMTIzCg== "ajouter | tr -d ' 'pour les couper:

> PASS=`awk -F":" '/pass/ {print $2 }' parameters.ini | tr -d ' ' | base64 --decode`
> echo "[$PASS]"
[Abc123]
Luis Hernandez
la source
0

Cela utilise le système perl et des expressions régulières propres:

cat parameters.ini | perl -0777ne 'print "$1" if /\[\s*parameters\.ini\s*\][\s\S]*?\sdatabase_version\s*=\s*(.*)/'
Christopher Tate
la source
0

La réponse de "Karen Gabrielyan" parmi les autres réponses était la meilleure, mais dans certains environnements, nous n'avons pas de problème, comme la boîte de réception typique, j'ai changé la réponse par le code ci-dessous.

trim()
{
    local trimmed="$1"

    # Strip leading space.
    trimmed="${trimmed## }"
    # Strip trailing space.
    trimmed="${trimmed%% }"

    echo "$trimmed"
}


  function parseIniFile() { #accepts the name of the file to parse as argument ($1)
        #declare syntax below (-gA) only works with bash 4.2 and higher
        unset g_iniProperties
        declare -gA g_iniProperties
        currentSection=""
        while read -r line
        do
            if [[ $line = [*  ]] ; then
                if [[ $line = [* ]] ; then 
                    currentSection=$(echo $line | sed -e 's/\r//g' | tr -d "[]")  
                fi
            else
                if [[ $line = *=*  ]] ; then
                    cleanLine=$(echo $line | sed -e 's/\r//g')
                    key=$(trim $currentSection.$(echo $cleanLine | cut -d'=' -f1'))
                    value=$(trim $(echo $cleanLine | cut -d'=' -f2))
                    g_iniProperties[$key]=$value
                fi
            fi;
        done < $1
    }
Ehsan Ahmadi
la source
Je ne suis pas tout à fait sûr de la probabilité que awk manque, mais sed, cut et une syntaxe relativement plus avancée comme la syntaxe sont disponibles.
Ondrej K.
La plupart des systèmes de fichiers racine initiaux implémentent / linuxrc ou / init en tant que script shell et incluent donc un shell minimal (généralement / bin / ash) ainsi que quelques utilitaires essentiels de l'espace utilisateur
Ehsan Ahmadi
Sûr. Je suis juste un peu surpris que vous construisiez votre busybox sans awk, mais toujours avec sed, cut et support pour divers "bashismes". Non pas que ce ne serait pas possible, je me demande juste. ;)
Ondrej K.
D'autres outils sont plus légers que awk. si vous écrivez un script dans initramfs avec les outils initramfs dans ubuntu distro, vous constaterez que vous n'avez pas awk et que d'autres outils comme sed, grep ... sont en fonctionnement minimal.
Ehsan Ahmadi
Bien sûr, je ne parle pas de GNU awk ou d'un autre awk complet, je me demande simplement combien on économise en configurant busybox pour ne pas inclure le support awk (surtout étant donné que les autres bits mentionnés ne sont pas supprimés de cette configuration). Peut-être que * buntu initrd en a un comme ça. Je m'interroge juste sur le combo / choix c'est tout.
Ondrej K.
0

Si Python est disponible, ce qui suit lira toutes les sections, clés et valeurs et les enregistrera dans des variables avec leurs noms suivant le format "[section] _ [clé]". Python peut lire correctement les fichiers .ini, nous l'utilisons donc.

#!/bin/bash

eval $(python3 << EOP
from configparser import SafeConfigParser

config = SafeConfigParser()
config.read("config.ini"))

for section in config.sections():
    for (key, val) in config.items(section):
        print(section + "_" + key + "=\"" + val + "\"")
EOP
)

echo "Environment_type:  ${Environment_type}"
echo "Environment_name:  ${Environment_name}"

config.ini

[Environment]
  type                = DEV
  name                = D01
Hans Deragon
la source
0

Vous pouvez utiliser un analyseur CSV xsv pour analyser les données INI.

cargo install xsv
$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
$ xsv select -d "=" - <<< "$( cat /etc/*release )" | xsv search --no-headers --select 1 "DISTRIB_CODENAME" | xsv select 2
xenial

ou à partir d'un fichier.

$ xsv select -d "=" - file.ini | xsv search --no-headers --select 1 "DISTRIB_CODENAME" | xsv select 2
k23j4
la source
0

Si vous utilisez des sections, cela fera le travail:

Exemple de sortie brute:

$ ./settings
[section]
SETTING_ONE=this is setting one
SETTING_TWO=This is the second setting
ANOTHER_SETTING=This is another setting

Analyse des expressions rationnelles:

$ ./settings | sed -n -E "/^\[.*\]/{s/\[(.*)\]/\1/;h;n;};/^[a-zA-Z]/{s/#.*//;G;s/([^ ]*) *= *(.*)\n(.*)/\3_\1='\2'/;p;}"
section_SETTING_ONE='this is setting one'
section_SETTING_TWO='This is the second setting'
section_ANOTHER_SETTING='This is another setting'

Maintenant tous ensemble:

$ eval "$(./settings | sed -n -E "/^\[.*\]/{s/\[(.*)\]/\1/;h;n;};/^[a-zA-Z]/{s/#.*//;G;s/([^ ]*) *= *(.*)\n(.*)/\3_\1='\2'/;p;}")"
$ echo $section_SETTING_TWO
This is the second setting
Yann Bizeul
la source
0

J'ai un joli one-liner (en supposant que vous avez phpet jqinstallé):

cat file.ini | php -r "echo json_encode(parse_ini_string(file_get_contents('php://stdin'), true, INI_SCANNER_RAW));" | jq '.section.key'
Midlan
la source