¿Cómo obtengo un valor INI dentro de un script de shell?


97

Tengo un archivo parameters.ini, como:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Quiero leer y usar la versión de la base de datos especificada en el archivo parameters.ini desde un script de shell bash para poder procesarlo.

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

¿Cómo haría esto?


2
¿Alguna de estas respuestas respeta las secciones?
ManuelSchneid3r

Respuestas:


83

¿Qué tal hacer grepping para esa línea y luego usar awk?

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

6
Esto incluirá espacios después de '='.

10
Para recortar espacios, agregue | tr -d ' 'al final.
kenorb

22
Ésta no es realmente una buena solución. Piense en tener 2 secciones [parameters.ini] y cada una tiene una variable 'database_version'. Entonces obtienes el valor dos veces.
nerdoc

4
sí, considere un analizador ini especializado como crudini, ya que hay muchos casos extremos que no se manejan con los anteriores
pixelbeat

3
Sigue siendo útil y más rápido para archivos ini básicos.
Cyril N.

51

Puede usar el analizador nativo de bash para interpretar los valores ini, mediante:

$ source <(grep = file.ini)

Archivo de muestra:

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

Para las variables de acceso, sólo tiene que imprimirlos: echo $var1. También puede usar matrices como se muestra arriba ( echo ${IPS[@]}).

Si solo desea un valor único, simplemente grep para él:

source <(grep var1 file.ini)

Para la demostración, consulte esta grabación en asciinema .

Es simple, ya que no necesita ninguna biblioteca externa para analizar los datos, pero tiene algunas desventajas. Por ejemplo:

  • Si tiene espacios entre =(nombre de variable y valor), primero debe recortar los espacios, por ejemplo

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

    O si no le importan los espacios (incluso en el medio), use:

      $ source <(grep = file.ini | tr -d ' ')
  • Para respaldar los ;comentarios, reemplácelos con #:

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
  • Las secciones no son compatibles (por ejemplo, si lo ha hecho [section-name], debe filtrarlas como se muestra arriba, por ejemplo grep =), lo mismo ocurre con otros errores inesperados.

    Si es necesario leer valor específico en la sección específica, uso grep -A, sed, awko ex).

    P.ej

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

    Nota: ¿Dónde -A5está el número de filas para leer en la sección? Reemplazar sourcecon catpara depurar.

  • Si tiene errores de análisis, ignórelos agregando: 2>/dev/null

Ver también:


1
pero ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))esto no funcionará: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. donde no hay una regla definida con líneas
Psychozoic

Intenté usar la fuente, pero cuando hago eco de $ var1, no devuelve nada. ¿Por qué?
A. Gh

@ A.Gh No estoy seguro, funciona para mí. Asegúrate de usar el shell Bash. Ver: asciinema.org/a/306481
kenorb

Esto habría sido elegante, pero no logró que funcionara en OS X (Catalina). Funciona desde el símbolo del sistema en zsh (shell predeterminado actual), pero una vez que lo pongo en un script, aparece el error syntax error near unexpected token '('. Con bash, falla silenciosamente tanto desde el indicador como desde el script.
MiRin

29

Bash no proporciona un analizador para estos archivos. Obviamente, puede usar un comando awk o un par de llamadas sed, pero si es bash-sacerdote y no quiere usar ningún otro shell, entonces puede probar el siguiente código oscuro:

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

Uso:

# 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 se puede encontrar en el sitio del blog The Old School DevOps .


3
Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si cambia la página enlazada.
alecxe

8
Normalmente soy yo quien hace comentarios como este; todo lo que puedo decir es que era joven y estúpido :-)
Fredrik Pihl

1
Si te gusta este fragmento, hay una mejora
albfan

3
Para que funcione correctamente, es necesario utilizar cfg_parser en lugar de cfg.parser
Wes

1
TYPO: "cfg.parser" debe ser "cfg_parser".
Septiembre

26

Sed one-liner, que tiene en cuenta las secciones. Archivo de ejemplo:

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

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

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

Digamos que quiere param2 de section2. Ejecute lo siguiente:

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

Te regalaré

def

3
sed -nr "/ ^ \ [SECTION2 \] / {: l /^\s*[^#].*/ p; n; / ^ \ [/ q; bl;}" file.conf # para obtener la sección completa sin comentarios para un archivo de estilo .conf con [SECCIÓN2] y # líneas de comentario estilo hash. Luego, haga grep para paramname si solo desea un parámetro.
gaoithe

mejor use direcciones de rango sed que leer las siguientes líneas:"/^\[section2\]/,/^\[/{...}"
cuenca

1
si en un Mac: brew install gnu-sedy luego utilizar gsed(de otro modo: sed: illegal option -- r)
frnhr

¿Alguien puede explicar cómo funciona la sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" expresión? gracias
foo_l

22

Solo incluye tu archivo .ini en el cuerpo de bash:

Archivo ejemplo.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

Archivo ejemplo.sh

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

2
Esta debería ser la respuesta seleccionada. Funciona con file.properties y es tolerante a fallas (archivo con una línea vacía en el interior). Gracias
Anthony

17
no maneja la parte [sección] de los archivos INI.
Septiembre

¡Esta es la mejor respuesta!
JavaSheriff

17
Con suerte, nadie agrega "rm -rf /" al archivo ini :(
HeyMan

1
Mucho más seguro en sub-shell: $ (. Example.ini; echo $ DBNAME)
Rich Remer

14

Todas las soluciones que he visto hasta ahora también se encuentran en líneas comentadas. Este no lo hizo, si el código de comentario es ;:

awk -F '=' '{if (! ($0 ~ /^;/) && $0 ~ /database_version/) print $2}' file.ini

2
Esta debería ser la respuesta aceptada ya que a) Maneja las líneas comentadas b) simple :)
Sudar

1
¡Esto es fantástico, ty @PenguinLust! Uso: 1. Se permiten comentarios de línea completa con prefijo de punto y coma (no se permiten comentarios de fin de línea en línea); 2. El espacio en blanco no se elimina del resultado (por lo tanto, si el archivo ini tiene 'a = 1', la búsqueda del script para 'a' se evalúa como '1').
AnneTheAgile

1
Para recortar espacios, agregue | tr -d ' 'al final.
Kenorb

Esto tiene el mismo problema que la respuesta sugerida; busca todas las instancias de "database_version"
Nubcake

12

una de más posibles soluciones

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

8

Muestra el valor de my_key en un my_file de estilo ini :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - no imprime nada por defecto
  • -e - ejecutar la expresión
  • s/PATTERN//p - mostrar cualquier cosa que siga este patrón en el patrón:
  • ^ - el patrón comienza al principio de la línea
  • \s - carácter de espacio en blanco
  • * - cero o muchos (espacios en blanco)

Ejemplo:

$ 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

Entonces:

Busque un patrón donde la línea comience con cero o muchos caracteres de espacio en blanco, seguida de la cadena my_key , seguida de cero o muchos caracteres de espacio en blanco, un signo igual, luego cero o muchos caracteres de espacio en blanco nuevamente. Muestre el resto del contenido en esa línea siguiendo ese patrón.


Su ejemplo no funciona (no se barimprime), al menos en Unix / OSX.
kenorb

7

sed

Puede usar sedpara analizar el archivo de configuración ini, especialmente cuando tiene nombres de sección como:

# 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

para que pueda usar el siguiente sedscript para analizar los datos anteriores:

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

esto convertirá los datos ini en este formato plano:

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

por lo que será más fácil de analizar el uso sed, awko readpor tener nombres de sección en cada línea.

Créditos y fuente: archivos de configuración para scripts de shell , Michael Grünewald


Alternativamente, puede usar este proyecto:, chilladx/config-parserun analizador de configuración usando sed.


¡Esto es genial! Estaba pensando en aplanarlo así, ¡pero esto es mucho más allá de lo que estaba a punto de hackear!
Grinch

6

Puede usar la crudiniherramienta para obtener valores ini, por ejemplo:

DATABASE_VERSION=$(crudini --get parameters.ini '' database_version)

Tenga en cuenta que está basado en Python, por lo que puede no ser adecuado, por ejemplo, para aplicaciones de Linux integradas.
Craig McQueen

Esto es parte de los repositorios estándar de Fedora (probado con 31). yum install crudini
musaraña

5

Para las personas (como yo) que buscan leer archivos INI desde scripts de shell (leer shell, no bash), he creado una pequeña biblioteca auxiliar que intenta hacer exactamente eso:

https://github.com/wallyhall/shini (licencia MIT, haz con ella lo que quieras. Lo he vinculado anteriormente incluyéndolo en línea ya que el código es bastante extenso).

Es algo más "complicado" que el simple sed líneas sugeridas anteriormente, pero funciona de manera muy similar.

La función lee en un archivo línea por línea, buscando marcadores de sección ( [section]) y declaraciones de clave / valor ( key=value).

En última instancia, obtiene una devolución de llamada a su propia función: sección, clave y valor.


@CraigMcQueen: esta noche agregué un soporte de escritura de calidad alfa. ¡No está "completo" por ningún tramo de la imaginación!
wally

¡Brillante! :-) Mayor
Jonathan

5

De manera similar a las otras respuestas de Python, puede hacer esto usando la -cbandera para ejecutar una secuencia de declaraciones de Python dadas en la línea de comando:

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

Esto tiene la ventaja de requerir solo la biblioteca estándar de Python y la ventaja de no escribir un archivo de script separado.

O use un documento aquí para una mejor legibilidad, así:

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

¿Qué pasa si quiero tomar una sección completa como Array usando este comando?
Debopam Parua

2

Algunas de las respuestas no respetan los comentarios. Algunos no respetan las secciones. Algunos reconocen solo una sintaxis (solo ":" o solo "="). Algunas respuestas de Python fallan en mi máquina debido a una captura diferente o al no poder importar el módulo sys. Todos son un poco escuetos para mí.

Así que escribí el mío, y si tienes un Python moderno, probablemente puedas llamar a esto desde tu shell Bash. Tiene la ventaja de adherirse a algunas de las convenciones comunes de codificación de Python e incluso proporciona mensajes de error sensibles y ayuda. Para usarlo, asígnele el nombre myconfig.py (NO lo llame configparser.py o puede intentar importarse a sí mismo), hágalo ejecutable y llámelo como

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

Aquí está mi código para Python 3.5 en 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))

2

simplicidad compleja

archivo ini

test.ini

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

script bash con lectura y ejecución

/ 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

luego, en otro script, obtengo los resultados del comando y puedo usar cualquier variable dentro

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

finalmente, desde la línea de comando, la salida es así

# ./test.sh 
value_2

¡Gran solución! ¡Gracias!
Michael

2

Aquí está mi versión, que analiza secciones y llena una matriz asociativa global g_iniProperties con ella. Tenga en cuenta que esto solo funciona con bash v4.2 y superior.

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
}

Y aquí hay un código de muestra que usa la función anterior:

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

1

Este script obtendrá los siguientes parámetros:

lo que significa que si su ini tiene:

pars_ini.ksh <ruta al archivo ini> <nombre del sector en el archivo Ini> <el nombre en el nombre = valor para devolver>

p.ej. cómo llamarlo:


[ ambiente ]

a = x

[DataBase_Sector]

DSN = algo


Luego llamando:

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

esto recuperará el siguiente "algo"

el 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`

1

Escribí un script de Python rápido y fácil para incluirlo en mi script de bash.

Por ejemplo, se llama a su archivo ini food.ini y en el archivo puede tener algunas secciones y algunas líneas:

[FRUIT]
Oranges = 14
Apples = 6

Copie este pequeño script Python de 6 líneas y guárdelo como 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])

Ahora, en su script bash puede hacer esto, por ejemplo.

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

o

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

Esto presupone:

  1. tienes Python instalado
  2. tiene instalada la biblioteca configparser (esto debería venir con una instalación estándar de python)

Espero que ayude : ¬)


Estaba buscando algo que hiciera exactamente esto, así que seguí el ejemplo y funciona bien. Olvidé que escribí esto !!!! Traté de votar por mí mismo pero, ¡ay, no puedo votar por mí mismo! ja ja
joe_evans

0

Mi versión del 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:]*//

0

Acabo de terminar de escribir mi propio analizador. Intenté usar varios analizadores que se encuentran aquí, ninguno parece funcionar tanto con ksh93 (AIX) como con bash (Linux).

Es un estilo de programación antiguo: analizar línea por línea. Bastante rápido ya que usó pocos comandos externos. Un poco más lento debido a toda la evaluación requerida para el nombre dinámico de la matriz.

El ini admite 3 sintaxis especiales:

  • includefile = archivo ini -> Cargar un archivo ini adicional. Útil para dividir ini en varios archivos o reutilizar alguna configuración
  • includedir = directorio -> Igual que includefile, pero incluye un directorio completo
  • includesection = section -> Copia una sección existente a la sección actual.

Usé toda esa sintaxis para tener un archivo ini bastante complejo y reutilizable. Útil para instalar productos al instalar un nuevo sistema operativo; lo hacemos mucho.

Se puede acceder a los valores con $ {ini [$ section. $ Item]}. La matriz DEBE definirse antes de llamar a esto.

Que te diviertas. ¡Espero que sea útil para alguien más!

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

0

Esta implementación utiliza awky tiene las siguientes ventajas:

  1. Solo devolverá la primera entrada coincidente
  2. Ignora las líneas que comienzan con un ;
  3. Recorta los espacios en blanco iniciales y finales, pero no los espacios en blanco internos

Versión formateada :

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

De una sola línea :

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

0

Cuando uso una contraseña en base64, pongo el separador ":" porque la cadena base64 puede tener "=". Por ejemplo (yo uso ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

En parameters.iniponer la línea pass:QWJjMTIzCg==, y finalmente:

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

Si la línea tiene espacios como "pass : QWJjMTIzCg== "agregar | tr -d ' 'para recortarlos:

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

0

Esto usa el sistema perl y expresiones regulares limpias:

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

0

La respuesta de "Karen Gabrielyan" entre otras respuestas fue la mejor, pero en algunos entornos no tenemos awk, como el típico busybox, cambié la respuesta por el siguiente código.

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
    }

No estoy completamente seguro de la probabilidad de que falte awk, pero hay disponibles sed, cut y una sintaxis similar a bash relativamente más avanzada.
Ondrej K.

La mayoría de los sistemas de archivos raíz iniciales implementan / linuxrc o / init como un script de shell y, por lo tanto, incluyen un shell mínimo (generalmente / bin / ash) junto con algunas utilidades esenciales de espacio de usuario
Ehsan Ahmadi

Por supuesto. Estoy un poco sorprendido de que construyeras tu busybox sin awk, pero aún con sed, cut y soporte para varios "bashisms". No es que no sea posible, solo me hace preguntarme. ;)
Ondrej K.

Otras herramientas son más ligeras que awk. si escribe un script en initramfs con initramfs-tools en ubuntu distro, encontrará que no tiene awk y también otras herramientas como sed, grep ... están en funcionamiento mínimo.
Ehsan Ahmadi

Claro, no estoy hablando de GNU awk u otro awk completo, solo me pregunto cuánto se ahorra configurando busybox para que no incluya el soporte de awk (especialmente dado que los otros bits mencionados no se eliminan de esa configuración). Podría ser que * buntu initrd tenga uno así. Solo me pregunto sobre el combo / elección, eso es todo.
Ondrej K.

0

Si Python está disponible, lo siguiente leerá todas las secciones, claves y valores y los guardará en variables con sus nombres siguiendo el formato "[sección] _ [clave]". Python puede leer archivos .ini correctamente, por lo que lo usamos.

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

0

Puede utilizar un analizador CSV xsv como análisis de datos 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

o de un archivo.

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

0

Si usa secciones, esto hará el trabajo:

Ejemplo de salida sin procesar:

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

Análisis de expresiones regulares:

$ ./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'

Ahora todos juntos:

$ 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

0

Tengo un buen resumen (suponiendo que lo tengas phpe jqinstalado):

cat file.ini | php -r "echo json_encode(parse_ini_string(file_get_contents('php://stdin'), true, INI_SCANNER_RAW));" | jq '.section.key'
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.