21

In bash when I access an array by index I get strange behavior if the array is a variable that was imported in the source of another bash script. What causes this behavior? How can it be fixed so an array that is sourced from another bash script behaves the same way as an array defined from within the running script?

${numbers[0]} evals to "one two three" and not "one" as it should.The full test I've tried to demonstrate this behavior is shown below:

Source of test.sh :

#!/bin/bash

function test {

    echo "Length of array:"
    echo ${#numbers[@]}

    echo "Directly accessing array by index:"
    echo ${numbers[0]}
    echo ${numbers[1]}
    echo ${numbers[2]}

    echo "Accessing array by for in loop:"
    for number in ${numbers[@]}
    do
        echo $number
    done

    echo "Accessing array by for loop with counter:"
    for (( i = 0 ; i < ${#numbers[@]} ; i=$i+1 ));
    do
        echo $i
        echo ${numbers[${i}]}
    done
}

numbers=(one two three)
echo "Start test with array from within file:"
test 

source numbers.sh
numbers=${sourced_numbers[@]}
echo -e "\nStart test with array from source file:"
test

Source of number.sh :

#!/bin/bash
#Numbers

sourced_numbers=(one two three)

Output of test.sh :

Start test with array from within file:
Length of array:
3
Directly accessing array by index:
one
two
three
Accessing array by for in loop:
one
two
three
Accessing array by for loop with counter:
0
one
1
two
2
three

Start test with array from source file:
Length of array:
3
Directly accessing array by index:
one two three
two
three
Accessing array by for in loop:
one
two
three
two
three
Accessing array by for loop with counter:
0
one two three
1
two
2
three
1
  • maybe shell debugging with set -vx will show you something. (Don't have time to experiment right now). Good luck. Commented May 2, 2012 at 13:40

1 Answer 1

19

The problem has nothing to do with sourcing; it's happening because the assignment numbers=${sourced_numbers[@]} doesn't do what you think it does. It converts the array (sourced_numbers) into a simple string, and stores that in the first element of numbers (leaving "two" "three" in the next two elements). To copy it as an array, use numbers=("${sourced_numbers[@]}") instead.

BTW, for number in ${numbers[@]} is the wrong way to loop through an array's elements, because it'll break on whitespace in the elements (in this case, the array contains "one two three" "two" "three", but the loop runs for "one", "two", "three", "two", "three"). Use for number in "${numbers[@]}" instead. Actually, it's good to get in the habit of double-quoting pretty much all variable substitutions (e.g. echo "${numbers[${i}]}"), as this is not the only place where leaving them unquoted could cause trouble.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.