Bir kabuk betiği içinde bir INI değerini nasıl alabilirim?


104

Bir parameters.ini dosyam var, örneğin:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

İşleyebilmem için, parameters.ini dosyasında belirtilen veritabanı sürümünü bir bash kabuk betiğinden okumak ve kullanmak istiyorum.

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

Bunu nasıl yaparım?


3
Bu cevaplardan herhangi biri bölümlere saygı duyuyor mu?
ManuelSchneid3r

Yanıtlar:


86

Bu satır için grep yapıp sonra awk kullanmaya ne dersiniz?

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

6
Bu, '=' sonrasındaki boşlukları içerecektir.

11
Boşlukları kırpmak | tr -d ' 'için sonuna ekleyin .
kenorb

23
Bu gerçekten iyi bir çözüm değil. Her biri bir 'database_version' değişkenine sahip 2 [parameters.ini] bölümü olduğunu düşünün. Değeri iki kez alırsınız.
nerdoc

4
evet lütfen crudini gibi özel bir ini ayrıştırıcı düşünün, çünkü yukarıda ele alınmayan birçok uç durum var
pixelbeat

3
Temel ini dosyaları için hala yararlı ve daha hızlı.
Cyril N.

57

İni değerlerini yorumlamak için bash yerel ayrıştırıcısını şu şekilde kullanabilirsiniz:

$ source <(grep = file.ini)

Örnek dosya:

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

Erişim değişkenler için tek yapmanız gereken onları baskı: echo $var1. Yukarıda gösterildiği gibi dizileri de kullanabilirsiniz ( echo ${IPS[@]}).

Yalnızca tek bir değer istiyorsanız, sadece bunun için grep:

source <(grep var1 file.ini)

Demo için asciinema'da bu kaydı kontrol edin .

Verileri ayrıştırmak için herhangi bir harici kütüphaneye ihtiyacınız olmadığı için basittir, ancak bazı dezavantajları da vardır. Örneğin:

  • =(Değişken adı ve değer) arasında boşluk varsa , önce boşlukları kırpmanız gerekir, örneğin

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

    Veya boşlukları önemsemiyorsanız (ortası dahil), şunu kullanın:

      $ source <(grep = file.ini | tr -d ' ')
    
  • ;Yorumları desteklemek için bunları şu şekilde değiştirin #:

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
    
  • Bölümler desteklenmez (örneğin, eğer öyleyse [section-name], daha sonra yukarıda gösterildiği gibi filtrelemelisiniz, örneğin grep =), diğer beklenmedik hatalar için de aynıdır.

    Belirli belirli bölümünde değerini kullanımını okumak gerekirse grep -A, sed, awkveya ex).

    Örneğin

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

    Not: -A5Bölümde okunacak satır sayısı nerede . Hata ayıklamak için sourceile değiştirin cat.

  • Herhangi bir ayrıştırma hatanız varsa, bunları ekleyerek yoksayın: 2>/dev/null

Ayrıca bakınız:


2
ama ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))bu işine yaramayacak: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. çizgilerle kesin bir kuralın olmadığı yerde
Psychozoic

Kaynağı kullanmayı denedim, ancak $ var1'i yinelediğimde hiçbir şey döndürmüyor. Neden?
A. Gh

@ A.Gh Emin değilim, benim için çalışıyor. Bash kabuğunu kullandığınızdan emin olun. Bakınız: asciinema.org/a/306481
kenorb

Bu zarif olurdu, ancak OS X'te (Catalina) çalışmasını sağlayamadı. Zsh'daki (mevcut varsayılan kabuk) komut isteminden çalışır, ancak bir betiğe koyduğumda hatayı alıyorum syntax error near unexpected token '('. Bash ile hem komut isteminden hem de komut dosyasından sessizce başarısız olur.
MiRin

30

Bash bu dosyalar için bir ayrıştırıcı sağlamaz. Açıkçası bir awk komutu veya birkaç sed çağrısı kullanabilirsiniz, ancak bash-rahibiyseniz ve başka bir kabuk kullanmak istemiyorsanız, aşağıdaki belirsiz kodu deneyebilirsiniz:

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

Kullanım:

# 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-ayrıştırıcısı The Old School DevOps blog sitesinde bulunabilir .


3
Bu bağlantı soruyu cevaplayabilirken, cevabın temel kısımlarını buraya eklemek ve referans için bağlantıyı sağlamak daha iyidir. Bağlantılı sayfa değişirse yalnızca bağlantı yanıtları geçersiz hale gelebilir.
alecxe

8
Normalde böyle yorumlar veren benim; Söyleyebileceğim tek şey genç ve aptal olduğum :-)
Fredrik Pihl

1
Bu pasajı beğendiyseniz, github.com/albfan/bash-ini-parser
albfan'da

3
Doğru çalışması için cfg.parser yerine cfg_parser kullanmanız gerekir
Wes

1
TYPO: "cfg.parser", "cfg_parser" olmalıdır.
Setop

28

Bölümleri hesaba katan tek satırlık Sed. Örnek dosya:

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

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

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

Bölüm2'den param2 istediğinizi varsayalım. Aşağıdakileri çalıştırın:

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

sana vereceğim

def

3
sed -nr "/ ^ \ [BÖLÜM2 \] / {: l / renew\s*[🖤#].*/ p; n; / ^ \ [/ q; bl;}" file.conf # tüm bölümü almak için [SECTION2] ve # karma stili yorum satırlarına sahip .conf stili bir dosya için yorum olmadan. O zaman sadece bir parametre istiyorsanız paramname için grep.
gaoithe

sed aralığı adreslerini sonraki satırları okumaktan daha iyi kullanın:"/^\[section2\]/,/^\[/{...}"
basin

1
Bir mac eğer: brew install gnu-sedve daha sonra kullanmak gsed(Aksi: sed: illegal option -- r)
frnhr

sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" İfadenin nasıl çalıştığını açıklayan var mı? teşekkür ederim
foo_l

21

.İni dosyanızı bash gövdesine eklemeniz yeterlidir:

Örnek.ini dosyası :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

Örnek.sh dosyası

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

3
Bu seçilen cevap olmalıdır. File.properties ile çalışır ve hataya dayanıklıdır (içinde boş satır bulunan dosya). Teşekkürler
Anthony

21
INI dosyalarının [bölüm] kısmını işlemez.
Setop

bu en iyi cevap!
JavaSheriff

17
Umarım kimse ini dosyasına "rm -rf /" eklemez :(
HeyMan

1
Alt kabukta çok daha güvenli: $ (. Example.ini; echo $ DBNAME)
Rich Remer

14

Şimdiye kadar gördüğüm tüm çözümler, yorumlanmış satırlara da çarptı. Yorum kodu ;:

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

2
Bu kabul edilen cevap olmalı çünkü a) Yorumlanmış satırları ele alıyor b) basit :)
Yorumlanmış işliyor

1
Bu harika, ty @PenguinLust! Kullanım: 1. Tam satır Yorumlara noktalı virgül önekiyle izin verilir (satır içi satır sonu yorumlarına izin verilmez); 2. Beyaz boşluk sonuçtan çıkarılmaz (yani, eğer ini dosyasında 'a = 1' varsa, o zaman komut dosyasının 'a' araması '1' olarak değerlendirilir).
AnneTheAgile

1
Boşlukları kırpmak | tr -d ' 'için sonuna ekleyin .
kenorb

Bu, önerilen yanıtla aynı soruna sahiptir; her "database_version" örneğini arar
Nubcake

12

olası çözümlerden biri

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

8

My_key değerini ini tarzı bir my_file dosyasında görüntüleyin :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - varsayılan olarak hiçbir şey yazdırmayın
  • -e - ifadeyi yürütün
  • s/PATTERN//p - kalıptaki bu kalıbı takip eden herhangi bir şeyi görüntüleyin:
  • ^ - desen satırın başında başlar
  • \s - boşluk karakteri
  • * - sıfır veya çok sayıda (boşluk karakteri)

Misal:

$ 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

Yani:

Satırın sıfır veya birçok boşluk karakteri ile başladığı, ardından my_key dizesinin , ardından sıfır veya birçok boşluk karakteri, eşittir işareti, ardından sıfır veya birçok boşluk karakteri ile başladığı bir kalıp bulun . Bu kalıbı takip eden satırdaki içeriğin geri kalanını görüntüleyin.


Örneğiniz bar, en azından Unix / OSX üzerinde çalışmıyor ( yazdırılmamış).
kenorb

7

Diğer Python cevaplarına benzer şekilde, bunu -ckomut satırında verilen bir dizi Python ifadesini yürütmek için bayrağı kullanarak yapabilirsiniz :

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

Bu, yalnızca Python standart kitaplığı gerektirme ve ayrı bir komut dosyası yazmama avantajına sahiptir.

Veya daha iyi okunabilirlik için burada bir belge kullanın, böylece:

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

Bu komutu kullanarak bütün bir bölümü Array olarak almak istersem ne olur?
Debopam Parua

7

sed

sedÖzellikle aşağıdaki gibi bölüm adlarınız olduğunda ini yapılandırma dosyasını ayrıştırmak için kullanabilirsiniz :

# 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

böylece sedyukarıdaki verileri ayrıştırmak için aşağıdaki komut dosyasını kullanabilirsiniz:

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

bu, ini verilerini bu düz biçime dönüştürecektir:

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

yüzden kullanarak ayrıştırılması daha kolay olacak sed, awkya da readher satırda bölüm isimleri alarak.

Krediler ve kaynak: Kabuk betikleri için yapılandırma dosyaları , Michael Grünewald


Alternatif olarak, bu projeyi kullanabilirsiniz:, chilladx/config-parserkullanarak bir yapılandırma ayrıştırıcısı sed.


Bu harika! Bunu böyle düzleştirmeyi düşünüyordum ama bu, birlikte kesmek üzere olduğum şeyin çok ötesinde!
grinch

6

crudiniİni değerlerini almak için aracı kullanabilirsiniz , örneğin:

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

Python tabanlı olduğundan, örneğin gömülü Linux uygulamaları için uygun olmayabileceğini unutmayın.
Craig McQueen

Bu, standart Fedora depolarının bir parçasıdır (31 ile test edilmiştir). yum install crudini
kır faresi

5

INI dosyalarını kabuk komut dosyalarından okumak isteyen insanlar için (bash değil, kabuğu okuyun) - tam olarak bunu yapmaya çalışan küçük bir yardımcı kitaplığı devre dışı bıraktım:

https://github.com/wallyhall/shini (MIT lisansı, istediğiniz gibi yapın. Kod oldukça uzun olduğu için bunu satır içi dahil yukarıya bağladım.)

sedYukarıda önerilen basit satırlardan biraz daha "karmaşık" - ancak çok benzer bir temelde çalışıyor.

İşlev, satır satır bir dosyada okur - bölüm işaretleyicileri ( [section]) ve anahtar / değer bildirimlerini ( key=value) arar .

Sonuçta, kendi işlevinize (bölüm, anahtar ve değer) bir geri arama alırsınız.


@CraigMcQueen - Bu gece çok alfa kalitesinde yazma desteği ekledim. Hayal gücünün herhangi bir uzantısı ile "tamamlanmış" değil!
wally

Parlak! :-) Major
Jonathan

2

Bazı cevaplar yorumlara saygı duymuyor. Bazıları bölümlere saygı göstermez. Bazıları yalnızca bir sözdizimini tanır (yalnızca ":" veya yalnızca "="). Bazı Python yanıtları, farklı captialization veya sys modülünü içe aktaramama nedeniyle makinemde başarısız oluyor. Hepsi benim için biraz fazla kısa.

Ben de kendim yazdım ve modern bir Python'unuz varsa, muhtemelen bunu Bash kabuğunuzdan çağırabilirsiniz. Bazı yaygın Python kodlama kurallarına uyma avantajına sahiptir ve hatta mantıklı hata mesajları ve yardım sağlar. Kullanmak için myconfig.py gibi bir ad verin (bunu configparser.py olarak adlandırmayın veya kendisini içe aktarmayı deneyebilir) çalıştırılabilir yapın ve şöyle adlandırın

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

İşte Linux'ta Python 3.5 için kodum:

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

karmaşık basitlik

ini dosyası

test.ini

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

okuma ve yürütme ile bash betiği

/ 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

sonra başka bir komut dosyasında komutun sonuçlarını kaynaklıyorum ve içindeki herhangi bir değişkeni kullanabilirim

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

son olarak komut satırından çıktı böylece

# ./test.sh 
value_2

Harika çözüm! Teşekkürler!
Michael

2

İşte benim sürümüm , bölümleri ayrıştıran ve onunla global ilişkisel bir g_iniProperties dizisi dolduruyor . Bunun yalnızca bash v4.2 ve üstü ile çalıştığını unutmayın .

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
}

Ve işte yukarıdaki işlevi kullanan örnek bir kod:

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

1

Bu komut dosyası aşağıdaki gibi parametreleri alacaktır:

yani ini'nizde:

pars_ini.ksh <ini dosyasına giden yol> <Ini dosyasındaki Sektörün adı> <addaki ad = döndürülecek değer>

Örneğin. nasıl adlandırılır:


[çevre]

a = x

[DataBase_Sector]

DSN = bir şey


Sonra aranıyor:

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

bu, aşağıdaki "bir şeyi" alacaktır

"pars_ini.ksh" komut dosyası:

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

Bash betiğime eklemek için hızlı ve kolay bir python betiği yazdım.

Örneğin, ini dosyanız çağrılır food.ini ve dosyada bazı bölümler ve bazı satırlar olabilir:

[FRUIT]
Oranges = 14
Apples = 6

Bu küçük 6 satır Python betiğini kopyalayın ve 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])

Şimdi, bash betiğinizde bunu örneğin yapabilirsiniz.

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

veya

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

Bu, şunları varsayar:

  1. Python kurulu
  2. yapılandırma ayrıştırıcı kitaplığınız kurulu (bu standart bir python kurulumuyla birlikte gelmelidir)

Umarım yardımcı olur : ¬)


Tam da bunu yapan bir şey arıyordum, bu yüzden örneği takip ettim ve gayet iyi çalışıyor. Bunu yazdığımı unuttum !!!! Kendime oy vermeye çalıştım ama ne yazık ki kendime oy veremiyorum !!! ha ha
joe_evans

0

Tek satırlık versiyonum

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

Kendi ayrıştırıcımı yazmayı yeni bitirdim. Burada bulunan çeşitli ayrıştırıcıları kullanmayı denedim, hiçbiri hem ksh93 (AIX) hem de bash (Linux) ile çalışmıyor.

Eski programlama tarzı - satır satır ayrıştırma. Birkaç harici komut kullandığı için oldukça hızlı. Dizinin dinamik adı için gereken tüm değerlendirmeler nedeniyle biraz daha yavaş.

İni 3 özel sözdizimini destekler:

  • includefile = ini dosyası -> Ek bir ini dosyası yükleyin. İni'yi birden çok dosyaya bölmek veya bazı yapılandırma parçalarını yeniden kullanmak için kullanışlıdır
  • dahil = dizin -> includefile ile aynıdır, ancak tam bir dizin içerir
  • includeection = section -> Mevcut bir bölümü geçerli bölüme kopyalayın.

Oldukça karmaşık, yeniden kullanılabilir ini dosyasına sahip olmak için tüm bu sözdizimini kullandım. Yeni bir işletim sistemi kurarken ürünleri yüklemek için kullanışlıdır - bunu çok yapıyoruz.

Değerlere $ {ini [$ section. $ İtem]} ile erişilebilir. Dizi bunu çağırmadan önce tanımlanmalıdır ZORUNLU.

İyi eğlenceler. Umarım başkası için yararlıdır!

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

Bu uygulama awkaşağıdaki avantajları kullanır ve bunlara sahiptir:

  1. Yalnızca eşleşen ilk girişi döndürür
  2. Bir ile başlayan satırları yoksayar ;
  3. Baştaki ve sondaki beyaz alanı kırpar, ancak dahili beyaz alanı kırmaz

Biçimlendirilmiş sürüm :

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

Tek satırlık :

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

0

Base64'te bir parola kullandığımda, ":" ayırıcısını koyarım çünkü base64 dizesinde "=" olabilir. Örneğin (kullanıyorum ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

In parameters.iniçizgisini koymak pass:QWJjMTIzCg==ve nihayet:

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

Satırda kırpmak için "pass : QWJjMTIzCg== "ekle gibi boşluklar varsa | tr -d ' ':

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

0

Bu, sistem perl ve temiz düzenli ifadeleri kullanır:

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

0

Diğer cevaplar arasında "Karen Gabrielyan" cevabı en iyisiydi ancak bazı ortamlarda, tipik meşgul kutusu gibi awk olmadığımız için cevabı aşağıdaki kodu değiştirdim.

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
    }

Awk'nin eksik olmasının ne kadar muhtemel olduğundan tam olarak emin değilim, ancak sed, cut ve nispeten daha gelişmiş bash benzeri sözdizimi mevcut.
Ondrej K.

Çoğu ilk kök dosya sistemi, / linuxrc veya / init'i bir kabuk komut dosyası olarak uygular ve bu nedenle, bazı temel kullanıcı alanı yardımcı programlarıyla birlikte minimum bir kabuk (genellikle / bin / ash) içerir
Ehsan Ahmadi

Elbette. Meşgul kutunuzu awk olmadan kurmanıza biraz şaşırdım, ancak yine de sed, cut ve çeşitli "bashizmler" için destek ile. Mümkün olmayacağından değil, sadece merak ediyorum ;)
Ondrej K.

Diğer araçlar awk'den daha hafiftir. ubuntu dağıtımında initramfs araçları ile initramfs içine komut dosyası yazarsanız, awk'ye sahip olmadığınızı ve sed, grep gibi diğer araçların da minimum düzeyde çalıştığını göreceksiniz.
Ehsan Ahmadi

Elbette, GNU awk veya diğer full-blow awk'tan bahsetmiyorum, sadece busybox'ı awk desteğini içermeyecek şekilde yapılandırarak ne kadar tasarruf sağlayacağını merak ediyorum (özellikle bahsedilen diğer bitlerin bu yapılandırmadan çıkarılmadığı dikkate alındığında). Şu * buntu initrd'de buna benzer bir tane olabilir. Sadece kombinasyonu / seçimi merak ediyorum, hepsi bu.
Ondrej K.

0

Python mevcutsa, aşağıdakiler tüm bölümleri, anahtarları ve değerleri okuyacak ve bunları "[bölüm] _ [anahtar]" biçimini izleyen adlarıyla değişkenlere kaydedecektir. Python, .ini dosyalarını düzgün bir şekilde okuyabilir, bu yüzden onu kullanırız.

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

INI verilerini ayrıştırmak için bir CSV ayrıştırıcı xsv kullanabilirsiniz .

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

veya bir dosyadan.

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

0

Bölümler kullanıyorsanız, bu işi yapacak:

Örnek ham çıktı:

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

Normal ifade ayrıştırma:

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

Şimdi hep birlikte:

$ 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

Güzel tek satırım var (sahip olduğunuzu phpve jqyüklediğinizi varsayalım ):

cat file.ini | php -r "echo json_encode(parse_ini_string(file_get_contents('php://stdin'), true, INI_SCANNER_RAW));" | jq '.section.key'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.