5

This has been asked several times, but none of the methods work. I would like to dynamically create arrays with array names taken from the variables. So lets start with just one array for now:

#!/bin/bash
i="aaa"
eval ${i}=("1")

results in

./1.sh: line 3: syntax error near unexpected token `('
./1.sh: line 3: `eval ${i}=("1")'

same result with:

$(eval ${i})=('1')
$(eval echo ${i})=('1')
$(eval "echo ${i}")=('1')

I do not want to eval everything, justthe array name. If it is possible I would like to avoid using eval at all

3 Answers 3

10

eval expects a string as the argument. You can't use ( unquoted, it has a special meaning in shell.

i=aaa
eval "$i=(1 2)"  # Use a string, $i will expand in double quotes.
echo ${aaa[1]}

You can also use declare or typeset instead of eval:

declare -a $i='(1 2)'

You still have to quote the parentheses and spaces.

To avoid eval completely, you can assign one by one:

#! /bin/bash
name=aaa
values=(1 2)
for ((i=0; i<${#values[@]}; ++i)) ; do
    read "$name[$i]" <<< "${values[i]}"
done
echo ${aaa[1]}
4
  • I have updated the question
    – meso_2600
    Apr 29, 2015 at 9:21
  • @meso_2600: I updated the answer.
    – choroba
    Apr 29, 2015 at 9:34
  • The read variant is fantastic! At last a alternative to eval! The problem with declare/typeset is that in functions the declared variable is local to the function.
    – t0r0X
    Mar 21, 2017 at 16:36
  • 1
    @t0r0X Use declare -g or declare -x within function to make it global/export.
    – Cromax
    Feb 6, 2018 at 23:54
0

Here is a way to load the array without using eval. It doesn't use the ( data ) construct - instead it uses an input string with your choice of delimiter - the example uses |

i=aaa
IFS='|' read -a "$i" <<<"1|2   with spaces"
printf '%s\n' "${aaa[@]}"

Output:

1
2   with spaces
0

You can use declare with dynamic names and values, and variable indirection to reference variables based upon their name. printf '%q' can help you "shell-escape" values so that they can be used during dynamic assignments.

#!/bin/bash
declare -a products=( phone computer )
printf 'Product: %s\n' "${products[@]}"
# Product: phone
# Product: computer
unset products

declare varName='products'
declare -a "${varName}"='( cell\ phone laptop\ computer )'
declare arrayRef="${varName}[@]"
printf 'Product: %s\n' "${!arrayRef}"
# Product: cell phone
# Product: laptop computer
unset "${varName}"

declare -a toCopy=( 'LED TV' '"Smart" car' )
declare -a "${varName}"="( $( printf '%q ' "${toCopy[@]}" ) )"
printf 'Product: %s\n' "${!arrayRef}"
# Product: LED TV
# Product: "Smart" car
unset "${varName}"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .