私はいくつかのbash ini解析スクリプトを見て、次のようなものを見ました。これここで何度使ったことがあり、それが私に効果があるかどうか調べたかったです。 iniファイルを1行ずつ複数回読み取るように見え、各パスは最終的に評価される関数を徐々に構成します。一部の特殊文字では機能しますが、他の文字では機能しません。ファイルの値に一重引用符または記号より大きいまたは小さい記号が含まれている場合、スクリプトは構文エラーを返します。他のシンボルも予期しない結果を招く可能性があります。このようなキャラクターに会ったらどうすればいいですか?
ini を解析する関数です。
#!/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 be =
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
}
iniファイル
[Section1]
value1=abc`def # unexpected EOF while looking for matching ``'
value2=ghi>jkl # syntax error near unexpected token `>'
value3=mno$pqr # executes ok but outputs "mnoqr"
value4=stu;vwx # executes ok but outputs "stu"
答え1
事実はあなたです。できる何かをすることはbash
あなたを意味するものではありませんしなければならない。
sh
(bash
など)スクリプトは、プログラムを起動したりテキスト処理コマンドを処理したりするための比較的簡単なラッパーとして最適です。 iniファイルの解析や操作など、より複雑な操作の場合は、他の言語がより適しています。perl
またはでスクリプトを書くことを検討しましたかpython
?どちらも良い.iniファイルパーサーを持っています。Config::INI
私はiniファイルを解析する必要があるときにPerlのモジュールを何度も使用しました。
ただし、bashでこれに固執する場合は、単一の変数を設定する代わりに連想配列を使用する必要があります。
次のように起動します。
#! /bin/bash
inifile='user1074170.ini'
# declare $config to be an associative array
declare -A config
while IFS='=' read -r key val ; do
config["$key"]="$val"
done < <(sed -E -e '/^\[/d
s/#.*//
s/[[:blank:]]+$|^[[:blank:]]+//g' "$inifile" )
# now print out the config array
set | grep '^config='
スクリプトsed
は[Section1]
、その行(実際に開く角かっこで始まるすべての行 -[
複数のセクションを持つiniファイルでこれを別々に処理する必要がある[1])を削除し、コメントと前後のスペースを削除します。ループwhile
は各行を読み取り、それを=
フィールド区切り文字として使用し、内容を$ key変数と$ val変数に割り当て、$ config配列に追加します。
出力:
config=([value1]="abc\`def" [value3]="mno\$pqr" [value2]="ghi>jkl" [value4]="stu;vwx" )
後でスクリプトで次のように配列エントリを使用できます。
$ echo value1 is "${config[value1]}"
value1 is abc`def
$ [ "${config[value4]}" = 'stu;vwx' ] && echo true
true
[1]awk
それとも、perl
「短絡」モードでファイルを便利に読み取る簡単な方法はありますか?段落は、1つ以上の空行で他のテキストブロックと区切られたテキストブロックとして定義されます。
たとえば、使用するには、[Section1]
上記のループに供給するawk
前に以下のスクリプトを挿入してください。sed
while
awk -v RS= -v ORS='\n\n' '/\[Section1\]/' "$inifile" | sed ...
"$inifile"
(もちろん、コマンドラインの最後からファイルを削除してください。sed
ファイルを抽出するためにすべての手間をかけた後、ファイルを再入力したくありません。[Section1]
)
この設定は、iniファイルから1つのセクションのみを抽出する場合は必ずしも必要ではORS
ありませんが、2つ以上のセクションを抽出する場合は段落を分離したままにするのに役立ちます。
答え2
私はこれが不完全な答えであることを知っていますが、augeasはMySQL.lns
ほとんどの答えを解析できるようです。存在するaugtool
:
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> set /augeas/load/testini/lens "MySQL.lns"
augtool> load
augtool> ls /files/root/
.ssh/ test.ini/
augtool> ls /files/root/test.ini
target/ = Section1
augtool> ls /files/root/test.ini/target/
value1/ = abc`def
value2/ = ghi>jkl
value3/ = mno$pqr
value4/ = stu
唯一混乱したのは最後のものですが、正直バグだとは思いません。.ini
ファイル内のセミコロンはコメントの始まりを示します。また、あなたのデータが実際にこのようなものであるかどうか尋ねたいと思います。
そのsed
場合は、その前にいくつかの設定を行い、未;
使用の文字値を設定してから後処理に戻すことができます。しかし、最終的にファイルが識別可能な構造を持つことができるように、いくつかの標準が必要です。
編集する:
PHPレンズでテストしましたが、次の値を引用して全体の結果を得ることができます。
[root@vlzoreman ~]# augtool
augtool> set /augeas/load/testini/lens "PHP.lns"
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> load
augtool> ls /files/root/test.ini/Section1/
value1 = abc`def
value2 = ghi>jkl
value3 = mno$pqr
value4 = stu;vwx
それ以外の場合は、MySQLレンズと同じくらい離れています。
編集#2:
これを書くためのよりきれいな方法があると確信していますが、次は使用例です。
[root@vlp-foreman ~]# bash bash.sh
Values for: Section1:
:: value1 is abc`def
:: value2 is ghi>jkl
:: value3 is mno$pqr
:: value4 is stu;vwx
Values for: Section2:
:: value1 is abc`def
スクリプトは次のとおりです。
#!/bin/bash
sections=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini | cut -f1 -d/)
for currentSection in $sections; do
echo "Values for: $currentSection:"
fields=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini/$currentSection | awk '{print $1}')
for currentField in $fields; do
currentValue=$(augtool -A --transform "PHP.lns incl /root/test.ini" print /files/root/test.ini/$currentSection/$currentField | cut -f2 -d=)
currentValue=$(echo $currentValue | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' | sed -e 's/^"//' -e 's/"$//')
echo -e "\t:: $currentField is $currentValue"
done
done
答え3
見てくださいcrudini
:https://www.pixelbeat.org/programs/crudini/
Ubuntuでは、それをインストールしてsudo apt install crudini
iniファイルから値を読み取ることができます。
$ value1=$(crudini --get "crudini.ini" "Section1" "value1")
crudiniは複数のiniファイル形式をサポートし、特殊文字を処理します。
crudini.ini
[Section1]
value1=abc`def
value2=ghi>jkl
value3=mno$pqr
value4=stu;vwx
読み値
$ for i in {1..4}; do crudini --get "crudini.ini" "Section1" "value$i"; done
abc`def
ghi>jkl
mno$pqr
stu;vwx
$