Skip to content
Advertisement

BASH – Create arrays from lines of csv file, where first entry is array name

I’m learning to script in Bash. I have an CSV file, which contains next lines:

numbers,one,two,three,four,five
colors,red,blue,green,yellow,white
custom-1,a,b,c,d,e
custom+2,t,y,w,x,z

Need to create arrays from this, where first entry is array name, eg.

number=(one,two,three,four,five)
colors=(red,blue,green,yellow,white)
custom-1=(a,b,c,d,e)
custom+2=(t,y,w,x,z)

Here is my script:

IFS=","
while read NAME VALUES ; do
    declare -a $NAME
    arrays+=($NAME)
    IFS=',' read -r -a $NAME <<< "${VALUES[0]}"
done < file.csv

When I try with csv file, containing only two first string (numbers and colors), code works well. And if i try to with number, colors, custom-1, custom-2, there is error during reading csv:

./script.sh: line 5: declare: `custom-1': not a valid identifier
./script.sh: line 7: read: `custom+2': not a valid identifier

because bash does not allow special characters in variable names, as far as I understand. Is there any way to avoid this?

Advertisement

Answer

As you cannot use the first column of your CSV file as bash array names one option would be to generate valid names using a counter (e.g. arrayN). If you want to access your data using the values of this first column you would also need to store them somewhere with the corresponding counter value. An associative array (declare -A names=()) would be perfect. Last but not least, the namerefs (declare -n arr=..., available starting with bash 4.3) will be convenient to store and access your data. Example:

declare -i cnt=1
declare -A names=()
while IFS=',' read -r -a line; do
  names["${line[0]}"]="$cnt"
  declare -n arr="array$cnt"
  unset line[0]
  declare -a arr=( "${line[@]}" )
  ((cnt++))
done < foo.csv

Now, to access the values corresponding to, let’s say, entry custom+2, first get the corresponding counter value, declare a nameref pointing to the corresponding array and voilĂ :

$ cnt="${names[custom+2]}"
$ declare -n arr="array$cnt"
$ echo "${arr[@]}"
t y w x z

Let’s declare a function for easier access:

getdata () {
  local -i cnt="${names[$1]}"
  local -n arr="array$cnt"
  [ -z "$2" ] && echo "${arr[@]}" || echo "${arr[$2]}"
}

And then:

$ getdata "custom+2"
t y w x z
$ getdata "colors"
red blue green yellow white
$ getdata "colors" 3
yellow
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement