Bagaimana cara mengambil nilai INI dalam skrip shell?


99

Saya memiliki file parameter.ini, seperti:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248

Saya ingin membaca dan menggunakan versi database yang ditentukan dalam file parameter.ini dari dalam skrip bash shell sehingga saya dapat memprosesnya.

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

Bagaimana saya melakukan ini?


2
Apakah salah satu dari jawaban ini menghormati bagian sama sekali?
ManuelSchneid3r

Jawaban:


85

Bagaimana kalau grep untuk baris itu lalu menggunakan awk

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

6
Ini akan mencakup spasi setelah '='.

11
Untuk memangkas spasi, tambahkan | tr -d ' 'di bagian akhir.
kenorb

23
Ini sebenarnya bukan solusi yang bagus. Pikirkan memiliki 2 bagian [parameter.ini] dengan masing-masing memiliki variabel 'database_version'. Anda mendapatkan nilainya dua kali.
nerdoc

4
ya mohon pertimbangkan parser ini khusus seperti crudini, karena ada banyak kasus tepi tidak ditangani oleh di atas
pixelbeat

3
Masih berguna dan lebih cepat untuk file ini dasar.
Cyril N.

52

Anda dapat menggunakan bash native parser untuk menafsirkan nilai ini, dengan:

$ source <(grep = file.ini)

File contoh:

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

Untuk variabel akses, Anda hanya mencetak mereka: echo $var1. Anda juga dapat menggunakan array seperti yang ditunjukkan di atas (echo ${IPS[@]} ).

Jika Anda hanya ingin satu nilai, grep saja:

source <(grep var1 file.ini)

Untuk demo, periksa rekaman ini di asciinema .

Ini sederhana karena Anda tidak memerlukan pustaka eksternal apa pun untuk mengurai data, tetapi ia memiliki beberapa kelemahan. Sebagai contoh:

  • Jika Anda memiliki spasi di antara =(nama dan nilai variabel), maka Anda harus memotong spasi terlebih dahulu, misalnya

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

    Atau jika Anda tidak peduli dengan ruang (termasuk di tengah), gunakan:

      $ source <(grep = file.ini | tr -d ' ')
  • Untuk mendukung ;komentar, gantilah dengan #:

      $ sed "s/;/#/g" foo.ini | source /dev/stdin
  • Bagian tidak didukung (mis. Jika Anda pernah [section-name], maka Anda harus memfilternya seperti yang ditunjukkan di atas, misgrep = ), sama untuk kesalahan tak terduga lainnya.

    Jika Anda perlu membaca nilai tertentu di bawah bagian tertentu, penggunaan grep -A, sed, awkatauex ).

    Misalnya

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

    Catatan: Di mana -A5jumlah baris untuk dibaca di bagian tersebut. Ganti sourcedengan catuntuk debug.

  • Jika Anda mendapatkan kesalahan penguraian, abaikan dengan menambahkan: 2>/dev/null

Lihat juga:


1
tetapi ... source <(grep = <(grep -A5 '\[section-b\]' file.ini))ini tidak akan berhasil untuk itu: [sec a] a = 1 b = 2 c = 3 [sec b] a = 2 b = 3 [sec c] a = 0. di mana tidak ada aturan yang pasti dengan garis
Psikozoikum

Saya mencoba menggunakan source, tetapi ketika saya menggemakan $ var1 itu tidak mengembalikan apa-apa. Mengapa?
A. Gh

@ A.Gh Saya tidak yakin, bekerja untuk saya. Pastikan Anda menggunakan Bash shell. Lihat: asciinema.org/a/306481
kenorb

Ini akan menjadi elegan, tetapi gagal membuatnya berfungsi di OS X (Catalina). Ini berfungsi dari command prompt di zsh (shell default saat ini), tetapi begitu saya memasukkannya ke dalam skrip, saya mendapatkan kesalahan syntax error near unexpected token '('. Dengan bash, itu diam-diam gagal baik dari prompt maupun skrip.
MiRin

30

Bash tidak menyediakan parser untuk file-file ini. Jelas Anda dapat menggunakan perintah awk atau beberapa panggilan sed, tetapi jika Anda bash-priest dan tidak ingin menggunakan shell lain, maka Anda dapat mencoba kode tidak jelas berikut:

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

Pemakaian:

# parse the config file called 'myfile.ini', with the following
# contents::
#   [sec2]
#   var2='something'
cfg.parser 'myfile.ini'

# enable section called 'sec2' (in the file [sec2]) for reading
cfg.section.sec2

# read the content of the variable called 'var2' (in the file
# var2=XXX). If your var2 is an array, then you can use
# ${var[index]}
echo "$var2"

Bash ini-parser dapat ditemukan di situs blog The Old School DevOps .


3
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah.
alecxe

8
Biasanya saya yang memberi komentar seperti ini; yang bisa saya katakan hanyalah bahwa saya masih muda dan bodoh :-)
Fredrik Pihl

1
Jika Anda menyukai cuplikan ini, ada peningkatan di github.com/albfan/bash-ini-parser
albfan

3
Untuk bekerja dengan benar, perlu menggunakan cfg_parser, bukan cfg.parser
Wes

1
TYPO: "cfg.parser" harus "cfg_parser".
Setop

26

Sed one-liner, yang memperhitungkan beberapa bagian. File contoh:

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

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

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

Katakanlah Anda menginginkan param2 dari bagian2. Jalankan perintah berikut:

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

akan memberimu

def

3
sed -nr "/ ^ \ [SECTION2 \] / {: l /^\s*[^#].*/ p; n; / ^ \ [/ q; bl;}" file.conf # untuk mendapatkan seluruh bagian tanpa komentar untuk file bergaya .conf dengan [SECTION2] dan # baris komentar bergaya hash. Kemudian grep untuk paramname jika Anda hanya ingin satu parameter.
gaoithe

lebih baik menggunakan alamat kisaran sed daripada membaca baris berikutnya:"/^\[section2\]/,/^\[/{...}"
cekungan

1
jika di mac: brew install gnu-seddan kemudian menggunakan gsed(sebaliknya: sed: illegal option -- r)
frnhr

Adakah yang bisa menjelaskan bagaimana sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" ekspresi itu bekerja? terima kasih
foo_l

21

Cukup sertakan file .ini Anda ke dalam bash body:

File example.ini :

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger

File example.sh

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

2
Ini harus menjadi jawaban yang dipilih. Ia bekerja dengan file.properties dan toleran terhadap kesalahan (file dengan baris kosong di dalamnya). Terima kasih
Anthony

18
tidak menangani bagian [bagian] dari file INI.
Setop

ini adalah jawaban terbaik!
JavaSheriff

17
Semoga tidak ada yang pernah menambahkan "rm -rf /" ke file ini :(
HeyMan

1
Jauh lebih aman di sub-shell: $ (. Example.ini; echo $ DBNAME)
Rich Remer

14

Semua solusi yang saya lihat sejauh ini juga sesuai dengan baris komentar. Yang ini tidak, jika kode komentarnya adalah ;:

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

2
Ini harus menjadi jawaban yang diterima karena a) Ini menangani baris yang dikomentari b) sederhana :)
Sudar

1
Ini luar biasa, ya @PenguinLust! Penggunaan: 1. Komentar baris penuh diperbolehkan dengan awalan titik koma (komentar akhir baris tidak diperbolehkan); 2. Spasi putih tidak dipisahkan dari hasil (jadi jika file ini memiliki 'a = 1', maka pencarian skrip untuk 'a' bernilai '1').
AnneTheAgile

1
Untuk memangkas spasi, tambahkan | tr -d ' 'di bagian akhir.
kenorb

Ini memiliki masalah yang sama dengan jawaban yang disarankan; itu mencari setiap contoh dari "database_version"
Nubcake

12

salah satu solusi yang lebih mungkin

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

8

Tampilkan nilai my_key dalam my_file gaya ini :

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
  • -n - jangan mencetak apa pun secara default
  • -e - jalankan ekspresinya
  • s/PATTERN//p - tampilkan apa pun yang mengikuti pola ini Dalam pola:
  • ^ - pola dimulai di awal baris
  • \s - karakter spasi
  • * - nol atau banyak (karakter spasi)

Contoh:

$ 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

Begitu:

Temukan pola di mana baris dimulai dengan nol atau banyak karakter spasi, diikuti oleh string my_key , diikuti oleh nol atau banyak karakter spasi, tanda sama dengan, kemudian nol atau banyak karakter spasi putih lagi. Tampilkan sisa konten di baris itu mengikuti pola itu.


Contoh Anda tidak berfungsi (tidak bardicetak), setidaknya di Unix / OSX.
kenorb

7

sed

Anda dapat menggunakan seduntuk mengurai file konfigurasi ini, terutama jika Anda memiliki nama bagian seperti:

# 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

sehingga Anda dapat menggunakan sedskrip berikut untuk mengurai data di atas:

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

ini akan mengubah data ini menjadi format datar ini:

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

sehingga akan lebih mudah untuk mengurai menggunakan sed, awkatau readdengan memiliki nama bagian di setiap baris.

Kredit & sumber: File konfigurasi untuk skrip shell , Michael Grünewald


Atau, Anda dapat menggunakan proyek ini chilladx/config-parser:, parser konfigurasi menggunakan sed.


Ini bagus! Saya berpikir untuk meratakannya seperti itu tetapi ini jauh melampaui apa yang akan saya retas bersama!
grinch

6

Anda dapat menggunakan crudinialat untuk mendapatkan nilai ini, misalnya:

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

Perhatikan bahwa ini didasarkan pada Python, jadi mungkin tidak cocok untuk misalnya aplikasi Linux yang disematkan.
Craig McQueen

Ini adalah bagian dari repo Fedora standar (diuji dengan 31). yum install crudini
shrewmouse

5

Untuk orang-orang (seperti saya) yang ingin membaca file INI dari skrip shell (baca shell, bukan bash) - Saya telah membuat pustaka pembantu kecil yang mencoba melakukan hal itu:

https://github.com/wallyhall/shini (Lisensi MIT, lakukan sesuka Anda. Saya telah menautkan di atas termasuk inline karena kodenya cukup panjang.)

Ini agak lebih "rumit" daripada sedbaris sederhana yang disarankan di atas - tetapi bekerja dengan dasar yang sangat mirip.

Fungsi membaca dalam file baris demi baris - mencari penanda bagian ( [section]) dan kunci / nilai deklarasi ( key=value).

Pada akhirnya Anda mendapatkan panggilan balik ke fungsi Anda sendiri - bagian, kunci, dan nilai.


@CraigMcQueen - Saya telah menambahkan beberapa dukungan tulis berkualitas alfa malam ini. Itu tidak "lengkap" oleh imajinasi mana pun!
wally

Cemerlang! :-) Mayor
Jonathan

5

Mirip dengan jawaban Python lainnya, Anda dapat melakukan ini menggunakan -cbendera untuk menjalankan urutan pernyataan Python yang diberikan pada baris perintah:

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

Ini memiliki keuntungan karena hanya membutuhkan pustaka standar Python dan keuntungan tidak menulis file skrip terpisah.

Atau gunakan dokumen di sini agar lebih mudah dibaca, dengan demikian:

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

Bagaimana jika saya ingin mengambil seluruh bagian sebagai Array menggunakan perintah ini?
Debopam Parua

2

Beberapa jawaban tidak menghargai komentar. Beberapa tidak menghormati bagian. Beberapa hanya mengenali satu sintaks (hanya ":" atau hanya "="). Beberapa jawaban Python gagal di mesin saya karena perbedaan huruf kapital atau gagal mengimpor modul sys. Semuanya agak terlalu singkat bagi saya.

Jadi saya menulis sendiri, dan jika Anda memiliki Python modern, Anda mungkin dapat memanggil ini dari shell Bash Anda. Ini memiliki keuntungan karena mengikuti beberapa konvensi pengkodean Python umum, dan bahkan menyediakan pesan kesalahan yang masuk akal dan bantuan. Untuk menggunakannya, beri nama seperti myconfig.py (JANGAN menyebutnya configparser.py atau mungkin mencoba mengimpor sendiri,) membuatnya dapat dieksekusi, dan menyebutnya seperti

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

Ini kode saya untuk Python 3.5 di 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

kesederhanaan yang kompleks

file ini

test.ini

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

bash script dengan membaca dan mengeksekusi

/ 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

kemudian di skrip lain saya mencari hasil dari perintah dan dapat menggunakan variabel apa pun di dalamnya

test.sh

#!/bin/bash

source parseini test.ini

echo $section2_name2

akhirnya dari baris perintah hasilnya adalah demikian

# ./test.sh 
value_2

Solusi bagus! Terima kasih!
Michael

2

Ini adalah versi saya, yang mem-parsing bagian dan mengisi array asosiatif global g_iniProperties dengannya. Perhatikan bahwa ini hanya berfungsi dengan bash v4.2 dan yang lebih tinggi.

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
}

Dan berikut ini contoh kode menggunakan fungsi di atas:

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

1

Script ini akan mendapatkan parameter sebagai berikut:

Artinya jika ini Anda memiliki:

pars_ini.ksh <jalur ke file ini> <nama Sektor di file Ini> <nama dalam nama = nilai untuk kembali>

misalnya. bagaimana menyebutnya:


[ lingkungan Hidup ]

a = x

[DataBase_Sector]

DSN = sesuatu


Kemudian menelepon:

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

ini akan mengambil "sesuatu" berikut

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

Saya menulis skrip python yang cepat dan mudah untuk disertakan dalam skrip bash saya.

Misalnya, file ini Anda dipanggil food.ini dan di dalam file Anda dapat memiliki beberapa bagian dan beberapa baris:

[FRUIT]
Oranges = 14
Apples = 6

Salin skrip Python 6 baris kecil ini dan simpan sebagai file 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])

Sekarang, di skrip bash Anda, Anda dapat melakukan ini misalnya.

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

atau

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

Ini mengandaikan:

  1. Anda telah menginstal Python
  2. Anda telah menginstal pustaka configparser (ini harus datang dengan instalasi std python)

Semoga membantu : ¬)


Saya sedang mencari sesuatu yang melakukan ini jadi saya mengikuti contoh dan bekerja dengan baik. Aku lupa aku menulis ini !!!! Saya mencoba untuk memilih diri saya sendiri tetapi, sayangnya, saya tidak dapat memilih untuk diri saya sendiri !!! ha ha
joe_evans

0

Versi saya dari satu baris

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

Baru saja selesai menulis parser saya sendiri. Saya mencoba menggunakan berbagai parser yang ditemukan di sini, sepertinya tidak ada yang berfungsi dengan ksh93 (AIX) dan bash (Linux).

Ini gaya pemrograman lama - mengurai baris demi baris. Cukup cepat karena menggunakan beberapa perintah eksternal. Sedikit lebih lambat karena semua eval yang diperlukan untuk nama dinamis array.

Ini mendukung 3 sintaks khusus:

  • Includefile = ini file -> Muat file ini tambahan. Berguna untuk memisahkan ini menjadi beberapa file, atau menggunakan kembali beberapa bagian konfigurasi
  • includeir = directory -> Sama seperti Includefile, tetapi sertakan direktori lengkapnya
  • includeection = section -> Salin bagian yang ada ke bagian saat ini.

Saya menggunakan semua sintaks itu untuk memiliki file ini yang cukup kompleks dan dapat digunakan kembali. Berguna untuk menginstal produk saat menginstal OS baru - kami sering melakukannya.

Nilai dapat diakses dengan $ {ini [$ section. $ Item]}. Array HARUS didefinisikan sebelum memanggil ini.

Selamat bersenang-senang. Semoga bermanfaat untuk orang lain!

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

Implementasi ini menggunakan awkdan memiliki keuntungan sebagai berikut:

  1. Hanya akan mengembalikan entri pertama yang cocok
  2. Mengabaikan baris yang dimulai dengan a ;
  3. Memangkas spasi kosong di depan dan di belakang, tetapi bukan spasi internal

Versi yang diformat :

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

Satu baris :

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

0

Ketika saya menggunakan kata sandi di base64, saya meletakkan pemisah ":" karena string base64 mungkin memiliki "=". Misalnya (saya gunakan ksh):

> echo "Abc123" | base64
QWJjMTIzCg==

Dalam parameters.inimenempatkan baris pass:QWJjMTIzCg==, dan akhirnya:

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

Jika garis memiliki spasi seperti "pass : QWJjMTIzCg== "tambahkan | tr -d ' 'untuk memangkasnya:

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

0

Ini menggunakan perl sistem dan ekspresi reguler yang bersih:

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

0

Jawaban dari "Karen Gabrielyan" di antara jawaban lainnya adalah yang terbaik tetapi di beberapa lingkungan kami tidak memiliki awk, seperti busybox biasa, saya mengubah jawaban dengan kode di bawah ini.

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
    }

Saya tidak sepenuhnya yakin seberapa besar kemungkinan awk itu hilang, tetapi sed, cut, dan bash yang relatif lebih canggih seperti sintaks tersedia.
Ondrej K.

Sebagian besar sistem file root awal menerapkan / linuxrc atau / init sebagai skrip shell dan dengan demikian menyertakan shell minimal (biasanya / bin / ash) bersama dengan beberapa utilitas ruang pengguna yang penting
Ehsan Ahmadi

Tentu. Saya hanya sedikit terkejut Anda akan membangun busybox Anda tanpa awk, tetapi masih dengan sed, cut dan dukungan untuk berbagai "bashisms". Bukannya itu tidak mungkin, hanya membuatku bertanya-tanya. ;)
Ondrej K.

Alat lain lebih ringan daripada awk. jika Anda menulis skrip ke initramfs dengan alat-alat initramfs di distro ubuntu, Anda akan menemukan bahwa Anda tidak memiliki awk dan juga alat-alat lain seperti sed, grep ... beroperasi minimal.
Ehsan Ahmadi

Tentu, saya tidak berbicara tentang GNU awk atau full blow awk, hanya bertanya-tanya berapa banyak yang dihemat dengan mengkonfigurasi busybox agar tidak menyertakan dukungan awk (khususnya mengingat bit lain yang disebutkan tidak dihapus dari konfigurasi itu). Bisa jadi * buntu initrd punya yang seperti itu. Hanya ingin tahu tentang kombo / pilihan itu saja.
Ondrej K.

0

Jika Python tersedia, berikut ini akan membaca semua bagian, kunci dan nilai dan menyimpannya dalam variabel dengan nama mereka mengikuti format "[section] _ [key]". Python dapat membaca file .ini dengan baik, jadi kami memanfaatkannya.

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

Anda dapat menggunakan parser CSV xsv sebagai pengurai data 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

atau dari file.

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

0

Jika menggunakan bagian, ini akan melakukan pekerjaan:

Contoh keluaran mentah:

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

Penguraian reguler:

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

Sekarang semuanya:

$ 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

Saya memiliki satu baris yang bagus (mengasumsikan Anda telah phpdan jqmenginstal):

cat file.ini | php -r "echo json_encode(parse_ini_string(file_get_contents('php://stdin'), true, INI_SCANNER_RAW));" | jq '.section.key'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.