如何将属性文件读入关联数组?

Ali*_*aka 9 bash shell-script associative-array

我想将属性文件中的属性读入关联数组。我该怎么做?

解析内容的细节:散列和等号。其他一切都是奖金。

属性文件内容示例:

# comment
a=value-a
b=http://prefix.suffix:8080/?key=value
c=password_with\\backslash-and=equals
Run Code Online (Sandbox Code Playgroud)

我希望从该文件中构造这个 bash 关联数组:

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

declare -p该关联数组的预期输出,注意${props[c]}只包含一个反斜杠,"\\"'\')。

Sté*_*las 6

使用真正的解析器,如perlConfig::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
)
Run Code Online (Sandbox Code Playgroud)

(也适用于zsh)。

实现一个完整的解析器bash需要大量的工作,意味着重新发明轮子。您可以使用简单的while read循环来实现一个好的子集,因为read内置函数需要与这些属性文件非常相似的输入格式:

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

(也适用于ksh93zsh,另外两个支持关联数组的类似 Bourne 的 shell)。

处理:

  • prop = value
  • prop: value
  • prop value
  • 行首的注释(!以及#可选的前导空格)
  • 反斜杠(如在foo\:\:bar=value含有分隔符或钥匙foo=\ barpassword_with\\backslash-and=equals你的样品中)。
  • 用反斜杠续行

但是,如果我们检查规范

  • 那不处理\n, \r, \uXXXX... 序列

  • LF 是唯一可识别的行分隔符(不是 CR 也不是 CRLF)。

  • FF 不被识别为空格(我们不能仅仅$IFS根据 shell 和版本将其添加到其中,\f不一定会被识别为 IFS 空格字符¹)。

  • 对于像 那样的输入foo: bar = ,它存储bar${props[foo]}而不是bar = (foo: bar:baz:虽然可以)。只有当属性的值包含一个(未转义的)定界符(:可选地由 SPC/TAB 字符=包围,可选地由 SPC/TAB 字符或一个或多个 SPC/TAB 字符的序列包围)并且位于末尾时,这才是一个问题。

  • 它被视为以\!or开头的注释行\#。只有名称以!or开头的属性才有问题#

  •   prop=1\
       2\
       3
    
    Run Code Online (Sandbox Code Playgroud)

我们得到1 2 3而不是123:连续行中的前导空格不会被忽略,因为它们应该是。


² IFS 空白字符,每个 POSIX 是[:space:]在语言环境中分类的字符(通常包括\f但不必),并且碰巧$IFS在 ksh88(POSIX 规范所基于的)和大多数 shell 中,那是仍然限于 SPC、TAB 和 NL。我发现在这方面唯一符合 POSIX 的 shell 是yash. ksh93并且bash(从 5.0 开始)还包括其他空格(例如 CR、FF、VT...),但仅限于单字节(在某些系统上(例如 Solaris)要小心,其中包括单字节的不间断空格在某些地区)


Léa*_*ris 5

这是 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
Run Code Online (Sandbox Code Playgroud)

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

Run Code Online (Sandbox Code Playgroud)

来自提供的数据样本的此脚本的输出:

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" )
Run Code Online (Sandbox Code Playgroud)


Ali*_*aka 2

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
}
Run Code Online (Sandbox Code Playgroud)

用法:

readPopertyFile "file.properties"
Run Code Online (Sandbox Code Playgroud)

将把属性读入名为 的关联数组变量中properties

* 在 bash 中工作。不知道其他的贝壳怎么样。

* 不会处理多行属性。

  • 使用 bash 参数扩展来设置变量将为您节省 2 个子 shell、2 个 echo、2 个管道和两个带有 `key=${line%=*}` 和 `value=${line#*=}` 的 cut 命令。如果文件很大的话,这不太清楚,但速度会快得多。 (2认同)