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?

Stephen Watkins
fonte
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)
Ali Lown
fonte
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:

Kenorb
fonte
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 .

Fredrik Pihl
fonte
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
Egridasov
fonte
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}"
Gustavo González
fonte
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
Opux
fonte
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
jm666
fonte
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.

Dean Rather
fonte
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.

Kenorb
fonte
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)
pixelbeat
fonte
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.

Wally
fonte
@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
argentpepper
fonte
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))
4dummies
fonte
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
The Lazy Coder
fonte
Ó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
Karen Gabrielyan
fonte
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`
jeo
fonte
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 : ¬)

joe_evans
fonte
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:]*//
Valentin Heinitz
fonte
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"
    }
user3637822
fonte
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
Andrew Newdigate
fonte
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]
Luis Hernandez
fonte
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*(.*)/'
Christopher Tate
fonte
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
    }
Ehsan Ahmadi
fonte
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
Hans Deragon
fonte
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
k23j4
fonte
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
Yann Bizeul
fonte
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'
Midlan
fonte