次のようなparameters.iniファイルがあります。
[parameters.ini]
database_user = user
database_version = 20110611142248
処理できるように、bashシェルスクリプト内から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
どうすればいいですか?
その行をgreppingしてからawkを使用するのはどうですか
version=$(awk -F "=" '/database_version/ {print $2}' parameters.ini)
次の方法で、bashネイティブパーサーを使用してini値を解釈できます。
$ source <(grep = file.ini)
サンプルファイル:
[section-a]
var1=value1
var2=value2
IPS=( "1.2.3.4" "1.2.3.5" )
変数にアクセスするには、単にそれらを印刷します:echo $var1
。上記の配列(echo ${IPS[@]}
)を使用することもできます。
単一の値のみが必要な場合は、単にgrepしてください:
source <(grep var1 file.ini)
外部ライブラリでデータを解析する必要がないため、単純ですが、いくつかの欠点があります。例えば:
=
(変数名と値)の間にスペースがある場合、最初にスペースをトリムする必要があります。
$ source <(grep = file.ini | sed 's/ *= */=/g')
または、スペース(中央を含む)を気にしない場合は、次を使用します。
$ source <(grep = file.ini | tr -d ' ')
;
コメントをサポートするには、コメントを#
に置き換えます。
$ sed "s/;/#/g" foo.ini | source /dev/stdin
セクションはサポートされていません(例:[section-name]
を使用している場合、上記のようにフィルターで除外する必要があります(例:grep =
)。他の予期しないエラーも同様です。
特定のセクションで特定の値を読み取る必要がある場合は、grep -A
、sed
、awk
、または ex
)を使用します。
例えば。
source <(grep = <(grep -A5 '\[section-b\]' file.ini))
注:-A5
は、セクションで読み取る行の数です。 source
をcat
に置き換えてデバッグします。
解析エラーがある場合は、2>/dev/null
を追加して無視してください。
参照: iniファイルを解析してbash配列変数に変換する方法? serverfault SE
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
}
使用法:
# 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は The Old School DevOps blog site にあります。
.iniファイルをbash本文に含めるだけです:
ファイルexample.ini:
DBNAME=test
DBUSER=scott
DBPASSWORD=tiger
ファイルexample.sh
#!/bin/bash
#Including .ini file
. example.ini
#Test
echo "${DBNAME} ${DBUSER} ${DBPASSWORD}"
セクションを考慮に入れたSedワンライナー。サンプルファイル:
[section1]
param1=123
param2=345
param3=678
[section2]
param1=abc
param2=def
param3=ghi
[section3]
param1=000
param2=111
param3=222
セクション2のparam2が必要だとします。以下を実行します。
sed -nr "/^\[section2\]/ { :l /^param2[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}" ./file.ini
あなたにあげます
def
可能な解決策の1つ
dbver=$(sed -n 's/.*database_version *= *\([^ ]*.*\)/\1/p' < parameters.ini)
echo $dbver
これまで見てきたすべてのソリューションは、コメントアウトされた行にもヒットしました。コメントコードが;
:
awk -F '=' '{if (! ($0 ~ /^;/) && $0 ~ /database_version/) print $2}' file.ini
my_keyの値をiniスタイルで表示しますmy_file:
sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
-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
そう:
行がゼロまたは多くの空白文字で始まり、その後に文字列my_keyが続き、その後にゼロまたは多くの空白文字、等号、そしてゼロまたは多くの空白文字が続くパターンを見つけます。そのパターンに続くその行に残りのコンテンツを表示します。
INI Shellスクリプト(bashではなくShellを読む)からのファイル)を読みたい人(私のような人)のために-まさにそれをしようとする小さなヘルパーライブラリをノックアップしました。
https://github.com/wallyhall/shini (MITライセンス、お好きなように使ってください。コードが非常に長いため、上記をインラインに含めてリンクしました。)
これは、上記で提案された単純なsed
行よりやや「複雑」ですが、非常によく似た動作をします。
関数はファイルを1行ずつ読み込みます-セクションマーカー([section]
)およびキー/値宣言(key=value
)。
最終的には、独自の関数(セクション、キー、値)へのコールバックを取得します。
crudini
ツールを使用して、ini値を取得できます。例:
DATABASE_VERSION=$(crudini --get parameters.ini '' database_version)
回答の中にはコメントを尊重しないものもあります。一部はセクションを尊重しません。構文を1つだけ認識するものもあります(「:」のみまたは「=」のみ)。いくつかのPython大文字と小文字の違いやsysモジュールのインポートに失敗したため、私のマシンで答えが失敗します。
だから私は自分で書いた。もしあなたが最新のPythonを持っているなら、おそらくBash Shellからこれを呼ぶことができるだろう。一般的なPythonコーディング規約に準拠しているという利点があります。また、賢明なエラーメッセージとヘルプも提供します。 .pyまたはそれ自体をインポートしようとする場合があります)、実行可能にし、次のように呼び出します
value=$(myconfig.py something.ini sectionname value)
Python 3.5 on 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 __== '__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))
他のPython回答と同様に、-c
フラグPythonコマンドラインで指定されたステートメントのシーケンスを実行する:
$ python3 -c "import configparser; c = configparser.ConfigParser(); c.read('parameters.ini'); print(c['parameters.ini']['database_version'])"
20110611142248
これには、Python標準ライブラリのみを必要とするという利点と、別個のスクリプトファイルを作成しないという利点があります。
または、読みやすくするためにヒアドキュメントを使用します。
#!/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
これが私のバージョンです。セクションを解析し、グローバル連想配列g_iniPropertiesを設定します。これはbash v4.2以降でのみ機能することに注意してください。
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
}
そして、上記の関数を使用したサンプルコードを次に示します。
parseIniFile "/path/to/myFile.ini"
for key in "${!g_iniProperties[@]}"; do
echo "Found key/value $key = ${g_iniProperties[$key]}"
done
特に次のようなセクション名がある場合は、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
したがって、次の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
}
これにより、iniデータがこのフラット形式に変換されます。
owner|name|John Doe
owner|organization|Acme Widgets Inc.
database|server|192.0.2.62
database|port|143
database|file|payroll.dat
そのため、すべての行にセクション名を付けることで、sed
、awk
、またはread
を使用して解析しやすくなります。
クレジットとソース: シェルスクリプトの構成ファイル 、MichaelGrünewald
または、次のプロジェクトを使用できます。 chilladx/config-parser
、sed
を使用した構成パーサー。
このスクリプトは、次のようにパラメーターを取得します。
あなたのiniが持っている場合:
pars_ini.ksh <iniファイルへのパス> <iniファイル内のセクターの名前> <返すname = valueの名前>
例えば。それを呼び出す方法:
[環境]
a = x
[データベース部門]
DSN =何か
次に呼び出す:
pars_ini.ksh /users/bubu_user/parameters.ini DataBase_Sector DSN
これにより、次の「何か」が取得されます
\#!/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`
Base64でパスワードを使用する場合、base64文字列に「=」が含まれている可能性があるため、セパレーター「:」を使用します。たとえば(ksh
を使用):
> echo "Abc123" | base64
QWJjMTIzCg==
parameters.ini
にpass:QWJjMTIzCg==
行を追加し、最後に:
> PASS=`awk -F":" '/pass/ {print $2 }' parameters.ini | base64 --decode`
> echo "$PASS"
Abc123
行に"pass : QWJjMTIzCg== "
のようなスペースがある場合、| tr -d ' '
を追加してそれらをトリミングします。
> PASS=`awk -F":" '/pass/ {print $2 }' parameters.ini | tr -d ' ' | base64 --decode`
> echo "[$PASS]"
[Abc123]
私は自分のbashスクリプトに含めるための迅速で簡単なpythonスクリプトを作成しました。
たとえば、iniファイルの名前はfood.ini
およびファイルには、いくつかのセクションといくつかの行を含めることができます。
[FRUIT]
Oranges = 14
Apples = 6
この小さな6行をコピーしますPythonスクリプトと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])
これで、たとえばbashスクリプトでこれを行うことができます。
OrangeQty=$(python configparser.py food.ini FRUIT Oranges)
または
ApplesQty=$(python configparser.py food.ini FRUIT Apples)
echo $ApplesQty
これは以下を前提としています。
それが役立つことを願っています:¬)
「Karen Gabrielyan」の答えは他の答えの中でも最高でしたが、典型的なbusyboxのようにawkがない環境では、以下のコードで答えを変更しました。
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
}
これはシステムPerlとクリーンな正規表現を使用します:
cat parameters.ini | Perl -0777ne 'print "$1" if /\[\s*parameters\.ini\s*\][\s\S]*?\sdatabase_version\s*=\s*(.*)/'
CSVパーサー xsv を解析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
またはファイルから。
$ xsv select -d "=" - file.ini | xsv search --no-headers --select 1 "DISTRIB_CODENAME" | xsv select 2
複雑なシンプルさ
iniファイル
test.ini
[section1]
name1=value1
name2=value2
[section2]
name1=value_1
name2 = value_2
読み取りおよび実行を伴うbashスクリプト
/ 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
その後、別のスクリプトでコマンドの結果を取得し、任意の変数を使用できます
test.sh
#!/bin/bash
source parseini test.ini
echo $section2_name2
最終的にコマンドラインからの出力はこうなります
# ./test.sh
value_2
ワンライナーの私のバージョン
#!/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:]*//
Pythonが利用可能な場合、以下はすべてのセクション、キー、および値を読み取り、 "[section] _ [key]"という形式の名前で変数に保存します。Pythonは.iniファイルを適切に読み取ることができるため、これを利用します。
#!/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
独自のパーサーの作成が終了しました。ここにあるさまざまなパーサーを使用しようとしましたが、ksh93(AIX)とbash(Linux)の両方で動作するようには見えません。
それは古いプログラミングスタイルです-行ごとに解析します。外部コマンドをほとんど使用しなかったため、かなり高速です。配列の動的な名前に必要なすべての評価のため、少し遅くなります。
Iniは3つの特別な構文をサポートしています。
これらすべての構文を使用して、非常に複雑で再利用可能なiniファイルを作成しました。新しいOSをインストールするときに製品をインストールするのに便利です。
値には$ {ini [$ section。$ item]}でアクセスできます。これを呼び出す前に配列を定義する必要があります。
楽しんで。それが他の誰かに役立つことを願っています!
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"
}
この実装はawk
を使用し、次の利点があります。
;
で始まる行を無視しますフォーマット済みバージョン:
awk -F '=' '/^\s*database_version\s*=/ {
sub(/^ +/, "", $2);
sub(/ +$/, "", $2);
print $2;
exit;
}' parameters.ini
ワンライナー:
awk -F '=' '/^\s*database_version\s*=/ { sub(/^ +/, "", $2); sub(/ +$/, "", $2); print $2; exit; }' parameters.ini