从配置文件中解析Bash数组

7
我需要在包含每个“部分”的文件中有一个数组,其中包含:
[array0]
value1=asdf
value2=jkl

[array1]
value1=1234
value2=5678

我希望能够像这样检索这些值:
echo ${array0[value1]}
echo ${array0[value2]}

echo ${array1[value1]}
echo ${array1[value2]}

任何想法如何实现这一点?(解释是额外的奖励)
我已经阅读了这些答案,但没有一个完全符合我的要求。 在BASH中读取配置文件而不使用“source” BASH从配置文件解析变量 Bash中类似于数组的数据结构(配置文件)

你必须使用Bash吗?如果使用Ruby和YAML或Python和JSON或Lua或其他一些工具,这种事情将变得非常简单。 - John Zwinck
我认为对于我正在做的事情,最好使用Bash。我需要使用screen命令和其他相关的东西。 - AJ Ferguson
提供一些关于你实际尝试做什么的更多细节会很有帮助。 - chepner
4个回答

7

使用bash v4和关联数组,将配置文件中的属性存储为实际的bash变量:

$ while read line; do 
    if [[ $line =~ ^"["(.+)"]"$ ]]; then 
        arrname=${BASH_REMATCH[1]}
        declare -A $arrname
    elif [[ $line =~ ^([_[:alpha:]][_[:alnum:]]*)"="(.*) ]]; then 
        declare ${arrname}[${BASH_REMATCH[1]}]="${BASH_REMATCH[2]}"
    fi
done < config.conf

$ echo ${array0[value1]}
asdf

$ echo ${array1[value2]}
5678

$ for i in "${!array0[@]}"; do echo "$i => ${array0[$i]}"; done
value1 => asdf
value2 => jkl

$ for i in "${!array1[@]}"; do echo "$i => ${array1[$i]}"; done
value1 => 1234
value2 => 5678

3

一种没有eval的、100%纯Bash的可能性:

#!/bin/bash

die() {
   printf >&2 "%s\n" "$@"
   exit 1
}

aryname=''
linenb=0
while read line; do
   ((++linenb))
   if [[ $line =~ ^[[:space:]]*$ ]]; then
      continue
   elif [[ $line =~ ^\[([[:alpha:]][[:alnum:]]*)\]$ ]]; then
      aryname=${BASH_REMATCH[1]}
      declare -A $aryname
   elif [[ $line =~ ^([^=]+)=(.*)$ ]]; then
      [[ -n aryname ]] || die "*** Error line $linenb: no array name defined"
      printf -v ${aryname}["${BASH_REMATCH[1]}"] "%s" "${BASH_REMATCH[2]}"
   else
      die "*** Error line $linenb: $line"
   fi
done

从标准输入读取。如果你想读取文件,请将 done 替换为:

done < "filename"

以下形式的行

space and funnŷ sÿmbòl=value that will have an equal sign: look = it's funny

被允许


我喜欢这个答案,但我发现使用array0[value1]比使用array0[0]更方便。它更适合我的需求。(更新后的问题) - AJ Ferguson
@AJFerguson 很高兴看到这篇文章!实际上,我不得不以非常不自然的方式调整一些东西以适应您最初的要求!让我编辑答案以适应您新的(更自然的)要求。 - gniourf_gniourf
@AJFerguson更改(简化)以适应您的新要求。 - gniourf_gniourf

1
你可以使用以下命令在bash脚本中声明数组: declare -a <array_name>=(value1 value2 value 3) 然后你可以像这样使用它们: echo ${<array_name>[index]} 编辑: 好的,如果要从配置文件构建数组,我建议为每个要创建的数组使用不同的文件。
以下是步骤: 1.配置文件(创建一个文件并将您的值放入其中)
100
200
300
2.脚本文件(从文件中读取值并准备一个数组)
    array=()
#设置数组 while IFS=$'\n' read -a config do array+=(${config}) done < file_name #访问值 echo ${array[0]} echo ${array[1]}
IFS表示分隔符,
-a指定要提取到的数组名称,以便您可以在while循环内部访问它们。

我理解如何声明和使用数组,但我的问题是从文件中解析数组。 - AJ Ferguson

0

我马上要出门了,但我认为你可以做类似这样的事情(未经测试),也许像@anubhava这样聪明的人会接手并完成它...

eval $(gawk -F= '/^\[/{name=gensub(/\[|\]/,"","g");x=0} /=/{print "name[",x++,"]=",$2," "}' config)

基本上,当它看到以"["开头的行时,它会在变量name中提取数组名称,并使用gensub()去掉方括号。然后,当它看到一行中有"="时,它输出数组名称和递增的索引"x",供eval使用。
我得走了 - 在这里查看stat -s的示例here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接