Bash – Making associative array based on another associative array

associative arraybash

I made an associative array as follows. To give a few details, the keys refer to specific files because I will be using this array in the context of a larger script (where the directory containing the files will be a getopts argument).

declare -A BAMREADS
echo "BAMREADS array is initialized"

BAMREADS[../data/file1.bam]=33285268
BAMREADS[../data/file2.bam]=28777698
BAMREADS[../data/file3.bam]=22388955

echo ${BAMREADS[@]}  # Output: 22388955 33285268 28777698
echo ${!BAMREADS[@]} # Output: ../data/file1.bam ../data/file2.bam ../data/file3.bam

So far, this array seems to behave as I expect. Now, I want to build another associative array based on this array. To be specific: my second array will have the same keys as my first one but I want to divide the values by a variable called $MIN.

I am not sure which of the following strategies is best and I can't seem to make either work.

Strategy 1: copy the array and modify the array?

MIN=33285268

declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
BAMFRACS=("${BAMREADS[@]}")

echo ${BAMFRACS[@]}  # Output: 22388955 33285268 28777698
echo ${!BAMFRACS[@]} # Output: 0 1 2

This is not what I want for the keys. Even if it works, I would then need to perform the operation I mentioned on all the values.

Stragegy 2: build the second array when looping through the first.

MIN=33285268

declare -A BRAMFRACS
echo "BAMFRACS array is initialized"

for i in $(ls $BAMFILES/*bam)
do
    echo $i
    echo ${BAMREADS[$i]}
    BAMFRACS[$i] = ${BAMREADS[$i]} 
done

echo ${BAMFRACS[@]}
echo ${!BAMFRACS[@]}


#When I run this, I get the following error which I am unsure how to solve:

../data/file1.bam
33285268
script.bash: line 108: BAMFRACS[../data/file1.bam]: No such file or directory
../data/file2.bam
28777698
script.bash: line 108: BAMFRACS[../data/file2.bam]: No such file or directory
../data/file3.bam
22388955
script.bash: line 108: BAMFRACS[../data/file3.bam]: No such file or directory

Thanks

Best Answer

Build the new array from the old:

MIN=33285268

declare -A BRAMFRACS
for key in "${!BAMREADS[@]}"; do
    BRAMFRACS[$key]=$(( ${BAMREADS[$key]} / MIN ))
done

Comments on your code:

  • Your first suggested code does not work as it copies the values from the associative array to the new array. The values automatically gets the keys 0, 1 and 2 but the original keys are not copied. You need to copy the array key by key as I have shown above. This way you assign the wanted value to the correct key.

  • Your second suggested code contains a syntax error in that it has spaces around = in an assignment. This is where the errors that you see come from. variable = value is interpreted as "the command variable executed with the operands = and value".

  • If you wish to iterate over a set of pathnames, don't use ls. Instead just do for pathname in "$BAMFILES"/*bam; do.

  • Quote you variable expansions.

  • Consider using printf instead of echo to output variable data.

Related:

Related Question