Como faço para obter um valor INI em um script de shell?


97

Eu tenho um arquivo parameters.ini, como:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Quero ler e usar a versão do banco de dados especificada no arquivo parameters.ini de dentro de um script de shell bash para que possa processá-lo.

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

Como eu faria isso?


2
Alguma dessas respostas respeita as seções?
— ManuelSchneid3r

Respostas:


83

Que tal fazer um grep para essa linha e depois usar awk

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

6
Isso incluirá espaços após '='.

10
Para cortar espaços, adicione | tr -d ' 'no final.
— Kenorb

22
Esta não é realmente uma boa solução. Pense em ter 2 seções [parameters.ini] com cada uma tendo uma variável 'database_version'. Você obtém o valor duas vezes então.
— nerdoc de

4
sim, por favor, considere um analisador especial de INI como crudini, já que há muitos casos
— extremos

3
Ainda útil e mais rápido para arquivos ini básicos.
— Cyril N.

51

Você pode usar o analisador nativo bash para interpretar os valores ini, por:

$ source <(grep = file.ini)

Arquivo de amostra:

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

Para variáveis de acesso, basta imprimi-los: echo $var1. Você também pode usar matrizes conforme mostrado acima ( echo ${IPS[@]}).

Se você deseja apenas um único valor, execute o grep:

source <(grep var1 file.ini)

Para a demonstração, verifique esta gravação em asciinema .

É simples porque você não precisa de nenhuma biblioteca externa para analisar os dados, mas tem algumas desvantagens. Por exemplo:

  • Se você tiver espaços entre =(nome da variável e valor), então você deve cortar os espaços primeiro, por exemplo

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

    Ou se você não se importa com os espaços (inclusive no meio), use:

      $ source <(grep = file.ini | tr -d ' ')
  • Para apoiar ;comentários, substitua-os por #:

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
  • As seções não são suportadas (por exemplo, se você tiver [section-name], então você terá que filtrar como mostrado acima, por exemplo grep =), o mesmo para outros erros inesperados.

    Se você precisa ler valor específico sob a seção específica, utilização grep -A, sed, awkou ex).

    Por exemplo

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

    Nota: Onde -A5está o número de linhas a serem lidas na seção. Substitua sourcepor catpara depurar.

  • Se você tiver algum erro de análise, ignore-o adicionando: 2>/dev/null

Veja também:


1
mas ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))isso não funcionará para ele: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. onde não há regra definida com linhas
— Psychozoic

Tentei usar o código-fonte, mas quando echo o $ var1, ele não retorna nada. Por quê?
— A. Gh

@ A.Gh não tenho certeza, funciona para mim. Certifique-se de usar o shell Bash. Veja: asciinema.org/a/306481
— kenorb

Isso teria sido elegante, mas não funcionou no OS X (Catalina). Funciona a partir do prompt de comando em zsh (shell padrão atual), mas quando coloco em um script, recebo o erro syntax error near unexpected token '('. Com o bash, ele falha silenciosamente tanto no prompt quanto no script.
— MiRin

29

O Bash não fornece um analisador para esses arquivos. Obviamente, você pode usar um comando awk ou algumas chamadas sed, mas se você for bash-priest e não quiser usar nenhum outro shell, poderá tentar o seguinte código obscuro:

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

O bash ini-parser pode ser encontrado no blog do The Old School DevOps .


3
Embora este link possa responder à pergunta, é melhor incluir as partes essenciais da resposta aqui e fornecer o link para referência. As respostas somente com link podem se tornar inválidas se a página vinculada mudar.
— alecxe

8
Normalmente sou eu que faço comentários como este; tudo que posso dizer é que eu era jovem e estúpido :-)
— Fredrik Pihl

1
Se você gostou deste snippet, há uma aplicação em github.com/albfan/bash-ini-parser
— albfan 01 de

3
Para funcionar corretamente, é necessário usar cfg_parser em vez de cfg.parser
— Wes

1
TYPO: "cfg.parser" deve ser "cfg_parser".
— Setop de

26

Sed one-liner, que leva as seções em consideração. Arquivo de exemplo:

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

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

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

Digamos que você queira o param2 da seção2. Execute o seguinte:

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

Darei à você

def

3
sed -nr "/ ^ \ [SECTION2 \] / {: l /^\s*[^#].*/ p; n; / ^ \ [/ q; bl;}" file.conf # para obter a seção inteira sem comentários para um arquivo no estilo .conf com [SECTION2] e # linhas de comentário no estilo hash. Então grep para paramname se você quiser apenas um parâmetro.
— gaoithe

é melhor usar endereços de intervalo de sed do que ler as próximas linhas:"/^\[section2\]/,/^\[/{...}"
— bacia

1
se sobre uma mac: brew install gnu-sede, em seguida, utilizar gsed(de outro modo: sed: illegal option -- r)
— frnhr

Alguém pode explicar como sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" funciona a expressão? obrigado
— foo_l

22

Basta incluir seu arquivo .ini no corpo do bash:

Arquivo example.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

Arquivo example.sh

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

2
Esta deve ser a resposta selecionada. Ele funciona com file.properties e é tolerante a falhas (arquivo com linha vazia dentro). Obrigado
— Anthony

17
não trata a parte [seção] dos arquivos INI.
— Setop de

Esta é a melhor resposta!
— JavaSheriff

17
Esperançosamente, ninguém nunca adiciona um "rm -rf /" ao arquivo ini :(
— HeyMan

1
Muito mais seguro no sub-shell: $ (. Example.ini; echo $ DBNAME)
— Rich Remer

14

Todas as soluções que vi até agora também atingiram as linhas comentadas. Este não fez, se o código do comentário for ;:

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

2
Esta deve ser a resposta aceita, pois a) lida com linhas comentadas b) simples :)
— Sudar

1
Isso é ótimo, ty @PenguinLust! Uso: 1. Comentários de linha completa permitidos com prefixo de ponto e vírgula (não são permitidos comentários de fim de linha embutidos); 2.O espaço em branco não é eliminado do resultado (portanto, se o arquivo ini tiver 'a = 1', a pesquisa do script por 'a' será avaliada como '1').
— AnneTheAgile

1
Para cortar espaços, adicione | tr -d ' 'no final.
— Kenorb

Isso tem o mesmo problema da resposta sugerida; ele procura por cada instância de "database_version"
— Nubcake

12

uma das mais soluções possíveis

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

8

Exibir o valor de my_key em um my_file estilo ini :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - não imprime nada por padrão
  • -e - executa a expressão
  • s/PATTERN//p - exibir qualquer coisa que siga este padrão no padrão:
  • ^ - o padrão começa no início da linha
  • \s - caractere de espaço em branco
  • * - zero ou muitos (caracteres de espaço em branco)

Exemplo:

$ 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

Assim:

Encontre um padrão onde a linha comece com zero ou muitos caracteres de espaço em branco, seguido pela string my_key , seguido por zero ou muitos caracteres de espaço em branco, um sinal de igual e, em seguida, zero ou muitos caracteres de espaço em branco novamente. Exiba o resto do conteúdo nessa linha seguindo esse padrão.


Seu exemplo não funciona (não barimpresso), pelo menos no Unix / OSX.
— Kenorb

7

sed

Você pode usar sedpara analisar o arquivo de configuração ini, especialmente quando tiver nomes de seção 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

então você pode usar o seguinte sedscript para analisar os dados acima:

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

isso converterá os dados ini neste formato simples:

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

então será mais fácil analisar usando sed, awkou readtendo nomes de seção em cada linha.

Créditos e fonte: arquivos de configuração para scripts de shell , Michael Grünewald


Alternativamente, você pode usar este projeto chilladx/config-parser:, um analisador de configuração usando sed.


Isso é ótimo! Eu estava pensando em achatá-lo assim, mas isso está muito além do que eu estava prestes a hackear juntos!
— grinch de

6

Você pode usar a crudiniferramenta para obter valores INI, por exemplo:

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

Observe que ele é baseado em Python, portanto, pode não ser adequado, por exemplo, para aplicativos Linux embarcados.
— Craig McQueen

Isso faz parte do repositório Fedora padrão (testado com 31). yum install crudini
— musaranho

5

Para pessoas (como eu) procurando ler arquivos INI de scripts de shell (leia shell, não bash) - eu criei uma pequena biblioteca auxiliar que tenta fazer exatamente isso:

https://github.com/wallyhall/shini (licença MIT, faça o que quiser. Vinculei acima, incluindo inline, pois o código é bastante extenso).

É um pouco mais "complicado" do que o simples sed linhas sugeridas acima - mas funciona em uma base muito semelhante.

A função lê um arquivo linha por linha - procurando marcadores de seção ( [section]) e declarações de chave / valor (key=value ).

Em última análise, você obtém um retorno de chamada para sua própria função - seção, chave e valor.


@CraigMcQueen - Eu adicionei algum suporte de gravação de qualidade alfa esta noite. Não está "completo" em nenhum esforço da imaginação!
— wally

Brilhante! :-) Major
— Jonathan

5

Semelhante às outras respostas Python, você pode fazer isso usando a -csinalização para executar uma sequência de instruções Python fornecidas na linha de comando:

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

Isso tem a vantagem de exigir apenas a biblioteca padrão do Python e a vantagem de não gravar um arquivo de script separado.

Ou use um documento aqui para melhor legibilidade, desta forma:

#!/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 eu quiser pegar uma seção inteira como Array usando este comando?
— Debopam Parua de

2

Algumas das respostas não respeitam comentários. Alguns não respeitam as seções. Alguns reconhecem apenas uma sintaxe (apenas ":" ou apenas "="). Algumas respostas Python falham em minha máquina por causa de captialização diferente ou falha ao importar o módulo sys. Todos são um pouco concisos para mim.

Então, eu escrevi o meu próprio e, se você tiver um Python moderno, provavelmente poderá chamá-lo de seu shell Bash. Ele tem a vantagem de seguir algumas das convenções de codificação comuns do Python e até mesmo fornecer mensagens de erro e ajuda sensatas. Para usá-lo, nomeie-o como myconfig.py (NÃO o chame de configparser.py ou ele pode tentar importar a si mesmo), torne-o executável e chame-o como

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

Este é meu código para Python 3.5 no 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

simplicidade complexa

arquivo ini

test.ini

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

script bash com leitura e execução

/ 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

então, em outro script, eu procuro os resultados do comando e posso usar qualquer variável dentro

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

finalmente a partir da linha de comando a saída é, portanto,

# ./test.sh 
value_2

Ótima solução! Obrigado!
— Michael

2

Aqui está minha versão, que analisa seções e preenche uma matriz associativa global g_iniProperties com ela. Observe que isso funciona apenas com bash v4.2 e 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
}

E aqui está um código de amostra usando a função acima:

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

1

Este script obterá os parâmetros a seguir:

o que significa que se o seu ini tiver:

pars_ini.ksh <caminho para o arquivo ini> <nome do setor no arquivo Ini> <o nome no nome = valor a ser retornado>

por exemplo. como chamá-lo:


[ meio Ambiente ]

a = x

[DataBase_Sector]

DSN = algo


Então ligando para:

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

isso irá recuperar o seguinte "algo"

o 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

Eu escrevi um script python rápido e fácil para incluir no meu script bash.

Por exemplo, seu arquivo ini é chamado food.ini e no arquivo você pode ter algumas seções e algumas linhas:

[FRUIT]
Oranges = 14
Apples = 6

Copie este pequeno script Python de 6 linhas e salve-o 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])

Agora, em seu script bash, você pode fazer isso, por exemplo.

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

ou

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

Isso pressupõe:

  1. você tem Python instalado
  2. você tem a biblioteca configparser instalada (isso deve vir com uma instalação std python)

Espero que ajude : ¬)


Eu estava procurando por algo que fizesse exatamente isso, então segui o exemplo e funcionou perfeitamente. Esqueci que escrevi isso !!!! Tentei votar em mim, mas, infelizmente, não posso votar em mim !!! ha ha
— joe_evans

0

Minha versão do 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

Acabei de escrever meu próprio analisador. Tentei usar vários analisadores encontrados aqui, nenhum parece funcionar com ksh93 (AIX) e bash (Linux).

É o estilo de programação antigo - análise linha por linha. Muito rápido, pois usa poucos comandos externos. Um pouco mais lento por causa de toda a avaliação necessária para o nome dinâmico do array.

O ini suporta 3 sintaxes especiais:

  • includefile = arquivo ini -> Carregar um arquivo ini adicional. Útil para dividir ini em vários arquivos ou reutilizar alguma parte da configuração
  • includedir = diretório -> O mesmo que includefile, mas inclui um diretório completo
  • includesection = section -> Copiar uma seção existente para a seção atual.

Usei toda essa sintaxe para obter um arquivo ini bastante complexo e reutilizável. Útil para instalar produtos ao instalar um novo sistema operacional - fazemos muito isso.

Os valores podem ser acessados ​​com $ {ini [$ section. $ Item]}. A matriz DEVE ser definida antes de chamá-la.

Diverta-se. Espero que seja útil para outra pessoa!

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 implementação usa awke tem as seguintes vantagens:

  1. Retornará apenas a primeira entrada correspondente
  2. Ignora linhas que começam com um ;
  3. Corta os espaços em branco à esquerda e à direita, mas não os espaços em branco internos

Versão formatada :

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 uso uma senha em base64, coloco o separador ":" porque a string de base64 pode ter "=". Por exemplo (eu uso ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

Em parameters.inicolocar a linha pass:QWJjMTIzCg==e, finalmente:

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

Se a linha tiver espaços, como "pass : QWJjMTIzCg== "adicionar | tr -d ' 'para cortá-los:

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

0

Isso usa o perl do sistema e expressões regulares limpas:

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

0

A resposta de "Karen Gabrielyan" entre outras respostas foi a melhor, mas em alguns ambientes não temos awk, como o típico busybox, mudei a resposta pelo código abaixo.

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
    }

Não estou totalmente certo de quão provável é que o awk esteja faltando, mas sed, cut e uma sintaxe relativamente mais avançada do tipo bash estão disponíveis.
— Ondrej K.

A maioria dos sistemas de arquivos raiz iniciais implementam / linuxrc ou / init como um script de shell e, portanto, incluem um shell mínimo (geralmente / bin / ash) junto com alguns utilitários essenciais de espaço do usuário
— Ehsan Ahmadi

Certo. Estou um pouco surpreso por você ter construído seu busybox sem awk, mas ainda com sed, cut e suporte para vários "bashisms". Não que isso não fosse possível, só me faz pensar. ;)
— Ondrej K.

Outras ferramentas são mais leves do que awk. se você escrever um script em initramfs com initramfs-tools na distro ubuntu, você descobrirá que não tem o awk e também outras ferramentas como sed, grep ... estão em operação mínima.
— Ehsan Ahmadi

Claro, não estou falando sobre GNU awk ou outro full blow awk, apenas me perguntando quanto alguém economiza configurando o busybox para não incluir suporte a awk (especialmente dado que os outros bits mencionados não são retirados dessa configuração). Pode ser que * buntu initrd tenha um assim. Apenas pensando sobre a combinação / escolha é tudo.
— Ondrej K.

0

Se o Python estiver disponível, o seguinte irá ler todas as seções, chaves e valores e salvá-los em variáveis ​​com seus nomes seguindo o formato "[seção] _ [chave]". Python pode ler arquivos .ini corretamente, então nós fazemos uso dele.

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

Você pode usar um analisador CSV xsv para analisar dados 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 de um arquivo.

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

0

Se estiver usando seções, isso fará o trabalho:

Exemplo de saída bruta:

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

Análise regexp:

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

Agora 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

Eu tenho um bom one-liner (supondo que você tenha 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'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.