如何在shell脚本中获取INI值?

Ste*_*ins 90 bash shell ubuntu

我有一个parameters.ini文件,例如:

[parameters.ini]
    database_user    = user
    database_version = 20110611142248
Run Code Online (Sandbox Code Playgroud)

我想读入并使用bash shell脚本中的parameters.ini文件中指定的数据库版本,以便我可以处理它.

#!/bin/sh    
# Need to get database version from parameters.ini file to use in script    
php app/console doctrine:migrations:migrate $DATABASE_VERSION
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

Ali*_*own 77

那么使用awk然后为该行进行grepping

version=$(awk -F "=" '/database_version/ {print $2}' parameters.ini)
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好的解决方案.想想有2个[parameters.ini]部分,每个部分都有一个'database_version'变量.你得到两倍的价值. (18认同)
  • 要修剪空格,请添加`| tr -d''`在最后. (8认同)
  • 这将包括'='之后的空格. (5认同)
  • 对于基本的 ini 文件仍然有用且速度更快。 (4认同)
  • 是的,请考虑一个专门的ini解析器,如crudini,因为有许多边缘情况不由上述处理 (3认同)

ken*_*orb 38

您可以使用bash native解析器来解释ini值,方法是:

$ source <(grep = file.ini)
Run Code Online (Sandbox Code Playgroud)

样本文件:

[section-a]
  var1=value1
  var2=value2
  IPS=( "1.2.3.4" "1.2.3.5" )
Run Code Online (Sandbox Code Playgroud)

要访问变量,只需打印它们:echo $var1.您也可以使用如上所示的数组(echo ${IPS[@]}).

如果你只需要一个值grep就可以了:

source <(grep var1 file.ini)
Run Code Online (Sandbox Code Playgroud)

它很简单,因为您不需要任何外部库来解析数据,但它有一些缺点.例如:

  • 如果=(变量名和值)之间有空格,那么首先要修剪空格,例如

    $ source <(grep = file.ini | sed 's/ *= */=/g')
    
    Run Code Online (Sandbox Code Playgroud)
  • 要支持;评论,请将其替换为#:

    $ source <(grep = file.ini | tr -d ' ')
    
    Run Code Online (Sandbox Code Playgroud)
  • 不支持这些部分(例如,如果你已经[section-name]过滤,如上所示,例如grep =),对于其他意外错误也是如此.

    如果您需要在特定的部分,阅读特定的值,使用grep -A,sed,awkex).

    例如

    $ sed "s/;/#/g" foo.ini | source /dev/stdin
    
    Run Code Online (Sandbox Code Playgroud)

    注意:-A5该部分中要读取的行数在哪里.替换sourcecat调试.

  • 如果您有任何解析错误,请通过添加以下内容忽略它们: 2>/dev/null

另请参见:如何将ini文件解析并转换为bash数组变量?在serverfault SE

  • 但是... `source &lt;(grep = &lt;(grep -A5 '\[section-b\]' file.ini))` 这对它不起作用:[sec a] a=1 b=2 c=3 [sec b] a=2 b=3 [sec c] a=0。没有明确的线条规则 (3认同)

Fre*_*ihl 28

Bash不为这些文件提供解析器,显然你可以使用awk代码或几个sed调用,但是如果你是bash-priest并且不想再使用它,那么你可以尝试以下模糊的代码:

#!/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
}
Run Code Online (Sandbox Code Playgroud)

用法:

# 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"
Run Code Online (Sandbox Code Playgroud)

可以在The Old School DevOps博客站点找到Bash ini-parser .

  • 我通常会发表这样的评论; 我只能说我年轻而愚蠢:-) (6认同)
  • 虽然此链接可能会回答这个问题,但最好在此处包含答案的基本部分并提供参考链接.如果链接的页面发生更改,则仅链接的答案可能会无效. (3认同)
  • 如果您喜欢这个片段,https://github.com/albfan/bash-ini-parser 上有一个增强功能 (3认同)
  • 要正常工作,需要使用cfg_parser而不是cfg.parser (3认同)
  • 错字:“cfg.parser”应该是“cfg_parser”。 (2认同)

小智 20

只需将.ini文件包含在bash正文中:

文件example.ini:

DBNAME=test
DBUSER=scott
DBPASSWORD=tiger
Run Code Online (Sandbox Code Playgroud)

文件example.sh

#!/bin/bash
#Including .ini file
. example.ini
#Test
echo "${DBNAME}   ${DBUSER}  ${DBPASSWORD}"
Run Code Online (Sandbox Code Playgroud)

  • 不处理INI文件的[section]部分. (13认同)
  • 希望没有人在ini文件中添加"rm -rf /":( (11认同)
  • 这应该是选定的答案.它与file.properties一起使用并且是容错的(内部有空行的文件).谢谢 (2认同)
  • 在子 shell 中更安全: $(. example.ini; echo $DBNAME) (2认同)

小智 20

Sed one-liner,考虑到部分.示例文件:

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

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

[section3]
param1=000
param2=111
param3=222
Run Code Online (Sandbox Code Playgroud)

假设你想要第2节中的param2.运行以下命令:

sed -nr "/^\[section2\]/ { :l /^param2[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}" ./file.ini
Run Code Online (Sandbox Code Playgroud)

会给你

def
Run Code Online (Sandbox Code Playgroud)

  • sed -nr "/^\\[SECTION2\\]/ { :l /^\s*[^#].*/ p; n; /^\\[/ q; bl; }" file.conf # to使用 [SECTION2] 和 # hash-style 注释行获取 .conf 样式文件的整个部分而没有注释。如果您只需要一个参数,则 grep 为 paramname 。 (3认同)
  • 如果在 Mac 上:“brew install gnu-sed”,然后使用“gsed”(否则:“sed:非法选项 -- r”) (2认同)
  • 谁能解释一下 `sed -nr "/^\[SECTION2\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; bl; }"`表达有效吗?谢谢 (2认同)

Opu*_*pux 13

到目前为止,我见过的所有解决方案也都在评论出来.如果评论代码是;:

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

  • 这应该是可接受的答案,因为a)处理注释掉的行b)简单:) (2认同)
  • 要修剪空格,请添加`| tr -d ' '` 最后。 (2认同)
  • 这与建议的答案有同样的问题;它搜索“database_version”的每个实例 (2认同)
  • 这确实更好,尽管它不能处理 `#` 注释(在 Linux conf 文件中大量使用),而且事实上只有最后一个值是有效的,所以插件修剪可能是:`awk -F ' =' '{if (!($0 ~ /^;/) &amp;&amp; !($0 ~ /^#/) &amp;&amp; $0 ~ /ca_db/) print $2}' sssd.conf | tr -d ' ' | 尾-n1` (2认同)

jm6*_*666 11

一种更可能的解决方案

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


pix*_*eat 9

您可以使用crudini工具获取 ini 值,例如:

DATABASE_VERSION=$(crudini --get parameters.ini '' database_version)
Run Code Online (Sandbox Code Playgroud)


Dea*_*her 8

在ini风格的my_file中显示my_key的值:

sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
Run Code Online (Sandbox Code Playgroud)
  • -n - 默认情况下不要打印任何内容
  • -e - 执行表达式
  • s/PATTERN//p - 显示此模式后的任何内容在模式中:
  • ^ - 模式从行的开头开始
  • \s - 空白字符
  • * - 零或多(空白字符)

例:

$ 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
Run Code Online (Sandbox Code Playgroud)

所以:

找到一个模式,其中行以零或许多空白字符开头,后跟字符串my_key,后跟零或许多空白字符,等号,然后再返回零或许多空白字符.在该模式之后显示该行上的其余内容.


arg*_*per 8

与其他 Python 答案类似,您可以使用该-c标志来执行命令行上给出的一系列 Python 语句:

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

这样做的优点是只需要 Python 标准库,而不需要编写单独的脚本文件。

或者使用 here 文档以获得更好的可读性,因此:

#!/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
Run Code Online (Sandbox Code Playgroud)


ken*_*orb 7

sed

您可以使用sed来解析 ini 配置文件,尤其是当您有像这样的部分名称时:

# 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
Run Code Online (Sandbox Code Playgroud)

所以你可以使用下面的sed脚本来解析上面的数据:

# 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
}
Run Code Online (Sandbox Code Playgroud)

这会将 ini 数据转换为这种平面格式:

owner|name|John Doe
owner|organization|Acme Widgets Inc.
database|server|192.0.2.62
database|port|143
database|file|payroll.dat
Run Code Online (Sandbox Code Playgroud)

所以它会更容易使用解析sedawk或者read通过在每行有节的名称。

积分和来源:shell 脚本的配置文件,Michael Grünewald


或者,您可以使用这个项目:chilladx/config-parser,一个使用sed.


wal*_*lly 5

对于希望从shell脚本读取INI文件(例如读取shell,而不是bash)的人(像我一样)-我打开了一个小助手库,它试图做到这一点:

https://github.com/wallyhall/shini(MIT许可证,请按需使用。由于代码很长,我已在上面链接了它的内嵌代码。)

它比sed上面建议的简单行稍微“复杂”了-但工作原理非常相似。

函数逐行读取文件-查找节标记([section])和键/值声明(key=value)。

最终,您将获得自己函数的回调-部分,键和值。