web-dev-qa-db-fra.com

Comment analyser et convertir le fichier INI en variables de tableau BASH?

J'essaie de convertir un fichier INI en variables de tableau Bash. L'échantillon INI est comme ci-dessous:

[foobar]
session=foo
path=/some/path

[barfoo]
session=bar
path=/some/path

donc celles-ci deviennent:

session[foobar]=foo
path[foobar]=/some/path
session[barfoo]=bar

etc.

En ce moment, je pouvais trouver seulement cette commande

awk -F'=' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" $2 }'

En outre, un autre problème est que cela ne prend pas d'espaces près de = en considération. Je pense que sed est probablement mieux adapté à cet emploi, mais je ne sais pas comment détenir et stocker une variable temporaire pour le nom de la section dans sed.

Donc toute idée de faire cela?

13
Flint

Gawk accepte les expressions régulières en tant que délimiteurs de champ. Ce qui suit élimine les espaces autour du signe égal, mais les préserve dans le reste de la ligne. Les citations sont ajoutées autour de la valeur afin que ces espaces soient préservés lorsque l'assignation Bash est effectuée. Je suppose que les noms de section seront des variables numériques, mais si vous utilisez Bash 4, il serait facile d'adapter cela pour utiliser des tableaux associatifs avec les noms de section eux-mêmes comme index.

awk -F ' *= *' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" "\"" $2 "\"" }'

Notez que vous voudrez peut-être aussi faire la suppression de l'espace que Khaled Spectacles (sur seulement 1 $ et la section) depuis que les noms de variable Bash ne peuvent pas contenir d'espaces.

De plus, cette méthode ne fonctionnera pas si les valeurs contiennent des signes égaux.

Une autre technique serait d'utiliser une bash while read boucle et effectuez les affectations car le fichier est lu, à l'aide de declare qui est à l'abri du contenu le plus malveillant.

foobar=1
barfoo=2  # or you could increment an index variable each time a section is found
while IFS='= ' read var val
do
    if [[ $var == \[*] ]]
    then
        section=$var
    Elif [[ $val ]]
    then
        declare "$var$section=$val"
    fi
done < filename

Encore une fois, des matrices associatives pourraient être assez facilement soutenues.

J'utiliserais simple python script pour ce travail car il a construit Ini INI analyseur :

#!/usr/bin/env python

import sys, ConfigParser

config = ConfigParser.ConfigParser()
config.readfp(sys.stdin)

for sec in config.sections():
    print "declare -A %s" % (sec)
    for key, val in config.items(sec):
        print '%s[%s]="%s"' % (sec, key, val)

et puis à Bash:

#!/bin/bash

# load the in.ini INI file to current BASH - quoted to preserve line breaks
eval "$(cat in.ini  | ./ini2arr.py)"

# test it:
echo ${barfoo[session]}

Bien sûr, il existe des implémentations plus courtes dans Awk, mais je pense que cela est plus lisible et plus facile à entretenir.

11
Michał Šrajer

Si vous souhaitez éliminer les espaces supplémentaires, vous pouvez utiliser la fonction intégrée gsub. Par exemple, vous pouvez ajouter:

gsub(/ /, "", $1);

Cela supprimera tous les espaces. Si vous souhaitez supprimer des espaces au début ou à la fin du jeton, vous pouvez utiliser

gsub(/^ /, "", $1);
gsub(/ $/, "", $1);
3
Khaled

Voici une solution pure bash.

Ceci est une nouvelle version améliorée de ce que Chilladx a affiché:

https://github.com/albfan/bash-ini-parser

Pour un exemple vraiment facile de suivre un exemple initial: après avoir téléchargé cela, copiez simplement les fichiers bash-ini-parser, et scripts/file.ini Pour le même répertoire, créez un script de test client à l'aide de l'exemple que j'ai fourni ci-dessous sur ce même répertoire.

source ./bash-ini-parser
cfg_parser "./file.ini"
cfg_section_sec2
echo "var2=$var2"
echo "var5[*]=${var5[*]}"
echo "var5[1]=${var5[1]}"

Voici quelques améliorations supplémentaires que j'ai faites au script Bash-Ini-Parser ...

Si vous souhaitez pouvoir lire des fichiers INI avec des terminaisons de ligne Windows ainsi que UNIX, ajoutez cette ligne à la fonction CFG_PARSER immédiatement après celui qui lit le fichier:

ini=$(echo "$ini"|tr -d '\r') # remove carriage returns

Si vous souhaitez lire des fichiers qui ont des autorisations d'accès restrictives, ajoutez cette fonction facultative:

# Enable the cfg_parser to read "locked" files
function Sudo_cfg_parser {

    # Get the file argument
    file=$1

    # If not "root", enable the "Sudo" prefix
    sudoPrefix=
    if [[ $EUID -ne 0 ]]; then sudoPrefix=Sudo; fi

    # Save the file permissions, then "unlock" the file
    saved_permissions=$($sudoPrefix stat -c %a $file)
    $sudoPrefix chmod 777 $file

    # Call the standard cfg_parser function
    cfg_parser $file

    # Restore the original permissions
    $sudoPrefix chmod $saved_permissions $file  
}
0
BuvinJ