Come prendo un valore INI all'interno di uno script di shell?


97

Ho un file parameters.ini, come ad esempio:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Voglio leggere e utilizzare la versione del database specificata nel file parameters.ini dall'interno di uno script della shell bash in modo da poterlo elaborare.

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

Come lo farei?


2
Qualcuna di queste risposte rispetta le sezioni?
ManuelSchneid3r

Risposte:


83

Che ne dici di grepping per quella linea e poi usare awk

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

6
Ciò includerà spazi dopo "=".

10
Per tagliare gli spazi, aggiungi | tr -d ' 'alla fine.
Kenorb

22
Questa non è davvero una buona soluzione. Pensa di avere 2 sezioni [parameters.ini] con ciascuna una variabile "database_version". Allora ottieni il valore due volte.
nerdoc

4
sì, per favore considera un parser ini specializzato come crudini, poiché ci sono molti casi limite non gestiti da quanto sopra
pixelbeat

3
Ancora utile e più veloce per i file ini di base.
Cyril N.

51

Puoi utilizzare il parser nativo di bash per interpretare i valori ini, tramite:

$ source <(grep = file.ini)

File di esempio:

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

Per le variabili di accesso, è semplicemente la stampa: echo $var1. Puoi anche usare gli array come mostrato sopra ( echo ${IPS[@]}).

Se vuoi solo un singolo valore, basta grep per questo:

source <(grep var1 file.ini)

Per la demo, controlla questa registrazione su asciinema .

È semplice in quanto non è necessaria alcuna libreria esterna per analizzare i dati, ma presenta alcuni svantaggi. Per esempio:

  • Se hai spazi tra =(nome e valore della variabile), devi prima tagliare gli spazi, ad es

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

    Oppure, se non ti interessano gli spazi (anche al centro), usa:

      $ source <(grep = file.ini | tr -d ' ')
  • Per supportare i ;commenti, sostituiscili con #:

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
  • Le sezioni non sono supportate (ad es. Se l'hai fatto [section-name], allora devi filtrarle come mostrato sopra, ad es. grep =), Lo stesso per altri errori imprevisti.

    Se avete bisogno di leggere valore specifico nella sezione specifica, l'utilizzo grep -A, sed, awko ex).

    Per esempio

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

    Nota: dove -A5è il numero di righe da leggere nella sezione. Sostituisci sourcecon catper eseguire il debug.

  • Se hai errori di analisi, ignorali aggiungendo: 2>/dev/null

Guarda anche:


1
ma ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))questo non funzionerà per questo: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. dove non esiste una regola definita con le linee
Psychozoic

Ho provato a usare source, ma quando echo $ var1 non restituisce nulla. Perché?
A. Gh

@ A.Gh non sono sicuro, funziona per me. Assicurati di utilizzare la shell Bash. Vedi: asciinema.org/a/306481
kenorb

Sarebbe stato elegante, ma non è riuscito a farlo funzionare in OS X (Catalina). Funziona dal prompt dei comandi in zsh (shell predefinita corrente), ma una volta inserito in uno script, ottengo l'errore syntax error near unexpected token '('. Con bash, fallisce silenziosamente sia dal prompt che dallo script.
MiRin

29

Bash non fornisce un parser per questi file. Ovviamente puoi usare un comando awk o un paio di chiamate sed, ma se sei bash-priest e non vuoi usare nessun'altra shell, puoi provare il seguente codice 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
}

Utilizzo:

# 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 può essere trovato sul sito del blog DevOps Old School .


3
Sebbene questo collegamento possa rispondere alla domanda, è meglio includere le parti essenziali della risposta qui e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia.
alecxe

8
Normalmente sono io a fare commenti come questo; tutto quello che posso dire è che ero giovane e stupido :-)
Fredrik Pihl

1
Se ti piace questo frammento, c'è un miglioramento su github.com/albfan/bash-ini-parser
albfan

3
Per funzionare correttamente, è necessario utilizzare cfg_parser invece di cfg.parser
Wes

1
TIPO: "cfg.parser" dovrebbe essere "cfg_parser".
Setop

26

Sed one-liner, che tiene conto delle sezioni. File di esempio:

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

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

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

Di 'che vuoi param2 dalla sezione2. Eseguire quanto segue:

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

ti darà

def

3
sed -nr "/ ^ \ [SECTION2 \] / {: l /^\s*[^#”.*/ p; n; / ^ \ [/ q; bl;}" file.conf # per ottenere l'intera sezione senza commenti per un file di stile .conf con [SECTION2] e # righe di commento in stile hash. Quindi grep per paramname se vuoi solo un parametro.
gaoithe

meglio usare indirizzi di intervallo sed piuttosto che leggere le righe successive:"/^\[section2\]/,/^\[/{...}"
bacino

1
se su un Mac: brew install gnu-sede quindi utilizzare gsed(altrimenti: sed: illegal option -- r)
frnhr

Qualcuno può spiegare come funziona l' sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" espressione? grazie
foo_l

22

Includi semplicemente il tuo file .ini nel corpo bash:

File esempio.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

File esempio.sh

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

2
Questa dovrebbe essere la risposta selezionata. Funziona con file.properties ed è a tolleranza di errore (file con una riga vuota all'interno). Grazie
Anthony

17
non gestisce la parte [sezione] dei file INI.
Setop

questa è la risposta migliore!
JavaSheriff

17
Si spera che nessuno aggiunga mai un "rm -rf /" al file ini :(
HeyMan

1
Molto più sicuro nella sotto-shell: $ (. Example.ini; echo $ DBNAME)
Rich Remer

14

Tutte le soluzioni che ho visto fino ad ora hanno colpito anche le righe commentate. Questo no, se il codice del commento è ;:

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

2
Questa dovrebbe essere la risposta accettata poiché a) Gestisce le righe commentate b) semplice :)
Sudar

1
È fantastico, ty @PenguinLust! Utilizzo: 1. Commenti a riga intera consentiti con il prefisso punto e virgola (non sono consentiti commenti di fine riga inline); 2. Lo spazio bianco non viene eliminato dal risultato (quindi se il file ini ha "a = 1", la ricerca dello script per "a" restituisce "1").
AnneTheAgile

1
Per tagliare gli spazi, aggiungi | tr -d ' 'alla fine.
Kenorb

Questo ha lo stesso problema della risposta suggerita; cerca ogni istanza di "database_version"
Nubcake

12

una delle più possibili soluzioni

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

8

Visualizza il valore di my_key in un my_file in stile ini :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - non stampa nulla per impostazione predefinita
  • -e - eseguire l'espressione
  • s/PATTERN//p - mostra tutto ciò che segue questo modello Nel modello:
  • ^ - il motivo inizia all'inizio della riga
  • \s - carattere di spazio bianco
  • * - zero o molti (caratteri di spazio)

Esempio:

$ 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

Così:

Trova un modello in cui la riga inizia con zero o molti caratteri di spazio, seguita dalla stringa my_key , seguita da zero o molti caratteri di spazio, un segno di uguale, quindi zero o molti caratteri di spazio. Mostra il resto del contenuto su quella riga seguendo quel modello.


Il tuo esempio non funziona (non barstampato), almeno su Unix / OSX.
Kenorb

7

sed

Puoi usarlo sedper analizzare il file di configurazione ini, specialmente quando hai nomi di sezioni come:

# 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

quindi puoi utilizzare il seguente sedscript per analizzare i dati sopra:

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

questo convertirà i dati ini in questo formato piatto:

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

quindi sarà più facile analizzare usando sed, awko readavendo nomi di sezione in ogni riga.

Riconoscimenti e fonte: file di configurazione per script di shell , Michael Grünewald


In alternativa, puoi utilizzare questo progetto chilladx/config-parser:, un parser di configurazione che utilizza sed.


È fantastico! Stavo pensando di appiattirlo in quel modo, ma questo è miglia oltre quello che stavo per hackerare insieme!
grinch

6

Puoi utilizzare lo crudinistrumento per ottenere valori ini, ad esempio:

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

Nota che è basato su Python, quindi potrebbe non essere adatto ad esempio per applicazioni Linux incorporate.
Craig McQueen

Questo fa parte dei repository Fedora standard (testato con 31). yum install crudini
toporagno

5

Per le persone (come me) che cercano di leggere file INI da script di shell (leggere shell, non bash) - ho messo in moto la piccola libreria di supporto che cerca di fare esattamente questo:

https://github.com/wallyhall/shini (licenza MIT, fallo come preferisci. Ho collegato sopra includendolo in linea poiché il codice è piuttosto lungo.)

È un po 'più "complicato" delle semplici sedlinee suggerite sopra, ma funziona in modo molto simile.

La funzione legge in un file riga per riga, cercando i marcatori di sezione ( [section]) e le dichiarazioni chiave / valore ( key=value).

Alla fine si ottiene una richiamata alla propria funzione: sezione, chiave e valore.


@ CraigMcQueen - Ho aggiunto stasera un supporto per la scrittura di qualità alfa. Non è "completo" con uno sforzo di immaginazione!
wally

Brillante! :-) Maggiore
Jonathan

5

Simile alle altre risposte Python, puoi farlo usando il -cflag per eseguire una sequenza di istruzioni Python fornite sulla riga di comando:

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

Questo ha il vantaggio di richiedere solo la libreria standard Python e il vantaggio di non scrivere un file di script separato.

Oppure usa un here document per una migliore leggibilità, quindi:

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

E se volessi prendere un'intera sezione come Array usando questo comando?
Debopam Parua

2

Alcune delle risposte non rispettano i commenti. Alcuni non rispettano le sezioni. Alcuni riconoscono solo una sintassi (solo ":" o solo "="). Alcune risposte Python non riescono sulla mia macchina a causa della diversa captializzazione o della mancata importazione del modulo sys. Sono tutti un po 'troppo concisi per me.

Quindi ho scritto il mio, e se hai un Python moderno, probabilmente puoi chiamarlo dalla tua shell Bash. Ha il vantaggio di aderire ad alcune delle convenzioni di codifica comuni di Python e fornisce anche messaggi di errore e aiuto sensibili. Per usarlo, chiamalo qualcosa come myconfig.py (NON chiamalo configparser.py o potrebbe tentare di importare se stesso) rendilo eseguibile e chiamalo come

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

Ecco il mio codice per Python 3.5 su 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

semplicità complessa

ini file

test.ini

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

bash script con lettura ed esecuzione

/ 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

quindi in un altro script provo i risultati del comando e posso utilizzare qualsiasi variabile all'interno

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

infine dalla riga di comando l'output è così

# ./test.sh 
value_2

Ottima soluzione! Grazie!
Michael

2

Ecco la mia versione, che analizza le sezioni e popola un array associativo globale g_iniProperties con esso. Nota che funziona solo con bash v4.2 e versioni successive.

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
}

Ed ecco un codice di esempio che utilizza la funzione sopra:

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

1

Questo script otterrà i parametri come segue:

il che significa che se il tuo ini ha:

pars_ini.ksh <percorso del file ini> <nome del settore nel file ini> <il nome nel nome = valore da restituire>

per esempio. come chiamarlo:


[ambiente]

a = x

[DataBase_Sector]

DSN = qualcosa


Quindi chiamando:

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

questo recupererà il seguente "qualcosa"

lo 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

Ho scritto uno script Python facile e veloce da includere nel mio script bash.

Ad esempio, il tuo file ini viene chiamato food.ini e nel file puoi avere alcune sezioni e alcune righe:

[FRUIT]
Oranges = 14
Apples = 6

Copia questo piccolo script Python a 6 righe e salvalo come 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])

Ora, nel tuo script bash potresti farlo per esempio.

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

o

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

Ciò presuppone:

  1. hai installato Python
  2. hai la libreria configparser installata (dovrebbe venire con un'installazione di python std)

Spero che aiuti : ¬)


Stavo cercando qualcosa che facesse proprio questo, quindi ho seguito l'esempio e funziona perfettamente. Dimenticavo di aver scritto questo !!!! Ho provato a votare per me ma, ahimè, non posso votare per me !!! ah ah
joe_evans

0

La mia versione della battuta

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

Ho appena finito di scrivere il mio parser. Ho provato a utilizzare vari parser trovati qui, nessuno sembra funzionare sia con ksh93 (AIX) che con bash (Linux).

È un vecchio stile di programmazione: analisi riga per riga. Abbastanza veloce poiché utilizzava pochi comandi esterni. Un po 'più lento a causa di tutta l'eval richiesta per il nome dinamico dell'array.

L'ini supporta 3 sintassi speciali:

  • includefile = ini file -> Carica un file ini aggiuntivo. Utile per suddividere ini in più file o riutilizzare qualche pezzo di configurazione
  • includedir = directory -> Uguale a includefile, ma include una directory completa
  • includeection = section -> Copia una sezione esistente nella sezione corrente.

Ho usato tutta questa sintassi per avere file ini piuttosto complessi e riutilizzabili. Utile per installare prodotti durante l'installazione di un nuovo sistema operativo: lo facciamo spesso.

È possibile accedere ai valori con $ {ini [$ section. $ Item]}. L'array DEVE essere definito prima di chiamarlo.

Divertiti. Spero sia utile per qualcun altro!

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

Questa implementazione utilizza awke presenta i seguenti vantaggi:

  1. Restituirà solo la prima voce corrispondente
  2. Ignora le righe che iniziano con a ;
  3. Taglia gli spazi bianchi iniziali e finali, ma non gli spazi bianchi interni

Versione formattata :

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

One-liner :

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

0

Quando utilizzo una password in base64, metto il separatore ":" perché la stringa base64 potrebbe avere "=". Ad esempio (io uso ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

In parameters.iniput the line pass:QWJjMTIzCg==, e infine:

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

Se la linea ha spazi come "pass : QWJjMTIzCg== "aggiungi | tr -d ' 'per tagliarli:

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

0

Questo utilizza il sistema perl e le espressioni regolari pulite:

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

0

La risposta di "Karen Gabrielyan" tra le altre risposte è stata la migliore ma in alcuni ambienti non abbiamo awk, come il tipico busybox, ho cambiato la risposta con il codice sottostante.

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
    }

Non sono del tutto sicuro di quanto sia probabile che manchi awk, ma sono disponibili sed, cut e una sintassi relativamente più avanzata simile a bash.
Ondrej K.

La maggior parte dei file system root iniziali implementano / linuxrc o / init come script di shell e quindi includono una shell minima (di solito / bin / ash) insieme ad alcune utilità essenziali per lo spazio utente
Ehsan Ahmadi,

Sicuro. Sono solo un po 'sorpreso che tu abbia costruito la tua busybox senza awk, ma comunque con sed, cut e supporto per vari "bashismi". Non che non sarebbe possibile, mi fa solo pensare. ;)
Ondrej K.

Altri strumenti sono più leggeri di awk. se scrivi script in initramfs con initramfs-tools in ubuntu distro, scoprirai che non hai awk e anche altri strumenti come sed, grep ... funzionano al minimo.
Ehsan Ahmadi,

Certo, non sto parlando di GNU awk o di altri awk in piena regola, mi chiedo solo quanto si risparmia configurando busybox in modo da non includere il supporto awk (specialmente dato che gli altri bit menzionati non sono stati eliminati da quella configurazione). Potrebbe essere che * buntu initrd ne abbia uno proprio così. Mi chiedevo solo combo / scelta, tutto qui.
Ondrej K.

0

Se Python è disponibile, quanto segue leggerà tutte le sezioni, chiavi e valori e li salverà in variabili con i loro nomi che seguono il formato "[sezione] _ [chiave]". Python può leggere correttamente i file .ini, quindi ne facciamo uso.

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

Puoi utilizzare un parser CSV xsv per analizzare i dati 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 da un file.

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

0

Se usi le sezioni, questo farà il lavoro:

Esempio di output grezzo:

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

Analisi dell'espressione regolare:

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

Ora tutti insieme:

$ 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

Ho un bel one-liner (supponendo che tu abbia phpe jqinstallato):

cat file.ini | php -r "echo json_encode(parse_ini_string(file_get_contents('php://stdin'), true, INI_SCANNER_RAW));" | jq '.section.key'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.