web-dev-qa-db-ja.com

プロパティファイルを連想配列に読み込む方法は?

プロパティファイル のプロパティを連想配列に読み込みます。 どうすればよいですか?

解析対象の詳細:ハッシュと等号。それ以外はすべてボーナスです。

プロパティファイルの内容の例:

# comment
a=value-a
b=http://prefix.suffix:8080/?key=value
c=password_with\\backslash-and=equals

このbash連想配列をそのファイルから構築したいのですが。

 declare -A props='(
  [a]="value-a"
  [b]="http://prefix.suffix:8080/?key=value"
  [c]="password_with\\backslash-and=equals" )'

(その連想配列でのdeclare -pの予期される出力。${props[c]}にはバックスラッシュが1つだけ含まれていることに注意してください。"\\"'\'です)。

7

Perlの-​​ Config::Properties モジュールのような実際のパーサーを使用してください。スクリプト全体をPerlで実行しますが、bashを使用する必要がある場合は、次のようにすることができます。

typeset -A props
while IFS= read -rd '' key && IFS= read -rd '' value; do
  props[$key]=$value
done < <(
  Perl -MConfig::Properties -l0 -e '
   $p = Config::Properties->new();
   $p->load(STDIN);
   print for $p->properties' < file.properties
)

zshでも動作します)。

bashに完全なパーサーを実装することは、多くの作業であり、ホイールの再発明を意味します。組み込みのreadは、これらのプロパティファイルに非常に類似した入力形式を想定しているため、単純なwhile readループで適切なサブセットを実装できます。

typeset -A props
while IFS=$':= \t' read key value; do
  [[ $key = [#!]* ]] || [[ $key = "" ]] || props[$key]=$value
done < file.properties

ksh93およびzsh、連想配列をサポートする他の2つのBourneのようなシェルでも動作します)。

それは処理します:

  • prop = value
  • prop: value
  • prop value
  • 行頭のコメント(!および#オプションの先行ブランクあり)
  • バックスラッシュエスケープ(区切り文字を含むキーの場合はfoo\:\:bar=value、サンプルではfoo=\ barまたはpassword_with\\backslash-and=equalsのように)。
  • バックスラッシュ付きの行継続

ただし、 仕様 に対してチェックすると

  • これは\n\r\uXXXX...シーケンスを処理しません
  • LFは、認識されている唯一の行区切り文字です(CRでもCRLFでもありません)。
  • FFは空白として認識されません($IFSはIFS空白文字ではないため、\fに追加することはできません)。
  • foo: bar =などの入力の場合、${props[foo]}ではなくbar =barを格納します(ただし、foo: bar:baz:でも問題ありません)。これは、プロパティの値に1つの(エスケープされていない)区切り文字(:オプションでSPC/TAB文字で囲まれている、=オプションでSPC/TAB文字で囲まれている、または1つ以上のSPC /のシーケンスが含まれている場合にのみ問題になりますTAB文字)と最後にあります。
  • \!または\#で始まるコメント行として扱われます。名前が!または#で始まるプロパティの問題のみ。
  • prop=1\
     2\
     3
    

    1 2 3の代わりに123を取得します。継続行の先頭のスペースは、本来あるべきように無視されません。

6

そのデータフォーマットの最も一般的なサブセットについては、 bash変数展開 と正規表現マッチングを使用して、短い関数を使用できます。

注:これは、行が^key = value$形式、または^#.*$および^!.*$(コメント)。コードを適応させるか、そうでなければデータを前処理する

$ cat /tmp/propdata 
k1 = v1
# A comment
k2 = v2and some s=t=u=f=f
! Another comment
k3 = v3

$ unset DATA
$ declare -A DATA

$ props(){ while read line || [[ -n $line ]]; do
[[ "$line" =~ ^#|^! ]] && continue;
if [[ "${line% =*}" ]]; then DATA[${line% =*}]="${line#*= }" ; fi ;
done < $1 ; }

$ props /tmp/propdata

$ echo "${DATA[k3]}"
v3
$ echo "${DATA[k2]}"
v2and some s=t=u=f=f

編集:キーと値の「=」の前後のスペースを削除するように更新されました

Edit2:コメントもフィルタリングします。

4
Alex Stragies
declare -A properties
function readPopertyFile
{
    while read line || [[ -n $line ]]; do
        key=`echo $line | cut -s -d'=' -f1`
        if [ -n "$key" ]; then
            value=`echo $line | cut -d'=' -f2-`
            properties["$key"]="$value"
        fi
    done < $1
}

使用法:

readPopertyFile "file.properties"

プロパティをpropertiesという名前の連想配列変数に読み込みます。

* bashで動作します。他のシェルについては知らない。

*複数行のプロパティを処理しません。

1

これがBash4 +のハウツーです

#!/usr/bin/env bash

declare -A properties

# Read with:
# IFS (Field Separator) =
# -d (Record separator) newline
# first field before separator as k (key)
# second field after separator and reminder of record as v (value)
while IFS='=' read -d $'\n' -r k v; do
  # Skip lines starting with sharp
  # or lines containing only space or empty lines
  [[ "$k" =~ ^([[:space:]]*|[[:space:]]*#.*)$ ]] && continue
  # Store key value into assoc array
  properties[$k]="$v"
  # stdin the properties file
done < file.properties

# display the array for testing
typeset -p properties

file.properties

# comment
a=value-a
b=http://prefix.suffix:8080/?key=value
c=password_with\\backslash-and=equals

d e=the d e value
  # comment

提供されたデータサンプルからのこのスクリプトの出力:

declare -A properties=(["d e"]="the d e value" [c]="password_with\\\\backslash-and=equals" [b]="http://prefix.suffix:8080/?key=value" [a]="value-a" )
0
Léa Gris