値に特定の文字を含めることができるiniファイルを解析する方法は?

値に特定の文字を含めることができるiniファイルを解析する方法は?

私はいくつかの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あなたを意味するものではありませんしなければならない

shbashなど)スクリプトは、プログラムを起動したりテキスト処理コマンドを処理したりするための比較的簡単なラッパーとして最適です。 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前に以下のスクリプトを挿入してください。sedwhile

awk -v RS= -v ORS='\n\n' '/\[Section1\]/' "$inifile" | sed ...

"$inifile"(もちろん、コマンドラインの最後からファイルを削除してください。sedファイルを抽出するためにすべての手間をかけた後、ファイルを再入力したくありません。[Section1]

この設定は、iniファイルから1つのセクションのみを抽出する場合は必ずしも必要ではORSありませんが、2つ以上のセクションを抽出する場合は段落を分離したままにするのに役立ちます。

おすすめ記事