Question

I need to have an array for each "section" in the file containing:

[array0]
value1=asdf
value2=jkl

[array1]
value1=1234
value2=5678

I want to be able to retrieve these values like this:

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

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

Any thoughts on how to accomplish this? (Explanations would be a bonus)

I've already read these anwsers but none do exactly what I want to do.

Read a config file in BASH without using "source"

BASH Parsing variables from config file

Array like data structure in bash (config file)?

Était-ce utile?

La solution

with bash v4, using associative arrays, store the properties from the config file as actual bash variables:

$ 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

Autres conseils

One eval-free, 100% pure Bash possibility:

#!/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

Reads on standard input. If you want to read from a file, change the done by:

done < "filename"

Lines of the form

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

are allowed

You can declare array in bash scripts with

declare -a <array_name>=(value1 value2 value 3)

Then you can use them like this

echo ${<array_name>[index]}

Edit:

Ok, to construct arrays from config file. I would recommend to have a different file for each array you would like to create.

So here are the steps

1.config file (create a file and place your values in it)

100
200
300

2.script file (read values from file and prepare an array)

    array=()

    #setup array
    while IFS=$'\n' read -a config
    do
      array+=(${config})
    done < file_name

    #access values
    echo ${array[0]}
    echo ${array[1]}

IFS denotes the delimiter
-a specifies the array name you want to extract to, so that you can access them inside the while loop.

I am about to go out, but I think you can do something like this (untested) and maybe someone clever , like @anubhava, will pick it up and finish it off...

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

Basically, when it sees a line starting with "[" it picks up the array name in the variable name and strips off the square brackets with gensub(). Then, when it sees a line with "=" in it, it outputs the array name and an increasing index "x" for eval to pick up.

Gotta dash - look at the examples for stat -s here.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top