属性を読みたいです。プロパティファイル連想配列として。どうすればいいですか?
解析対象の詳細:ハッシュと等号。他のすべてはボーナスです。
プロパティファイルの内容の例:
# 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
(この連想配列noteの期待される出力には${props[c]}
1つのバックスラッシュしか含まれていません。"\\"
)'\'
。
答え1
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
多くの作業が必要で、車輪を再開発する必要があります。組み込み関数には次のプロパティファイルと非常によく似た入力形式が必要なので、while read
単純なループを使用して良いサブセットを得ることができます。read
typeset -A props
while IFS=$':= \t' read key value; do
[[ $key = [#!]* ]] || [[ $key = "" ]] || props[$key]=$value
done < file.properties
(連想配列をサポートする2つの異なるBourne様シェルインksh93
と一緒に使用することもできます)。zsh
これは以下を処理します。
prop = value
prop: value
prop value
- コメントは行の先頭にあります(オプション
!
で#
先行スペースがあります)。 - バックスラッシュエスケープ(区切り文字またはを含むキーの例のように
foo\:\:bar=value
)foo=\ bar
password_with\\backslash-and=equals
- バックスラッシュを使用した行の連続
ところで確認してみると仕様
\n
、、...シーケンスを処理しません\r
。\uXXXX
LFは唯一認識される行区切り文字です(CRまたはCRLFではありません)。
$IFS
FFは空白として認識されません(シェルとバージョンによっては必ずしも\f
IFS空白文字1として認識されるわけではないため、ここに追加することはできません)。のような入力の場合は、代わりに
foo: bar =
保存してくださいbar
(しかしそれも動作します)。属性値に(エスケープされていない)区切り文字(オプションでSPC / TAB文字で囲まれているか、オプションでSPC / TAB文字で囲まれているか、1つ以上のSPC / TAB文字シーケンス)が含まれていて、最後にある場合にのみ問題が発生します。 。${props[foo]}
bar =
foo: bar:baz:
:
=
\!
またはで始まるコメント行として扱われます\#
。名前またはで始まる属性にのみ!
問題があります#
。存在する
prop=1\ 2\ 3
私たちが得ることは、1 2 3
連続123
した行の先行スペースが無視されないことです。
²IFS スペース文字[:space:]
、各POSIXはロケール(通常は含まれていますが\f
必須ではありません)として分類された文字で、正確に$IFS
ksh88(POSIX仕様に基づいています)であり、ほとんどのシェルではまだSPC、TAB、およびNLに制限されています。これに関して私が見つけた唯一のPOSIX互換シェルはですyash
。ksh93
(bash
5.0ベース)他のスペース(CR、FF、VTなど)も含まれていますが、シングルバイトスペースに制限されています(たとえば、Solaris)(一部の領域にはシングルバイトの切り捨て防止スペースが含まれています)
答え2
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" )
答え3
このデータ型の最も一般的なサブセットでは、次のように短い関数を使用できます。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
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
。
*バッシュで動作します。他の殻についてはよくわかりません。
* 複数行属性は処理されません。