iteration on a mix of array and associative

85 Views Asked by At

I have the following script:

declare -A as1
declare -A as2
declare -a arr=()
declare -A sup

as1[file]="file1"
as2[file]="file2"

echo "test: ${as1[file]} ${as2[file]}"

i=1
arr+=(as$i)
i=2
arr+=(as$i)

for index in "${arr[@]}";
do
   declare -n temp="$index"
   echo "${temp[file]}"
done

sup[arr]=$arr

echo "try to print:"
for el in "${!sup[@]}"
do
   item=${sup[$el]}
    for index in "${item[@]}";
    do
       declare -n temp="$index"
       echo "${temp[file]}"
    done
done

It basically build an associative array of an array. In the array there are two associative arrays. I am not sure if it is too much complicated but it should work. The problem is the output is the following:

test: file1 file2
file1
file2
try to print:
file1

where the last line 'file2' is missing. I suppose there is an error in the last loop but I can't catch it. Any help?

EDIT1

The following script:

declare -A as1
declare -A as2
declare -a arr=()
declare -A sup

as1[file]="file1"
as2[file]="file2"

echo "test: ${as1[file]} ${as2[file]}"

i=1
arr+=(as$i)
i=2
arr+=(as$i)

echo "test1:"
for index in "${arr[@]}";
do
   declare -n temp="$index"
   echo "${temp[file]}"
done

sup[arr]=arr

echo "test2:"
for el in "${sup[@]}" ; do
  declare -n items="$el"
  for item in "${items[@]}" ; do
    declare -n temp="$item"
    echo "${temp[file]}"
  done
done

makes the following output:

test: file1 file2
test1:
file1
file2
test2:
file1
file2
file1
file2

it seems it loops two times

EDIT2

I am still have issues in applying this to a real case. I have created the following directories and files:

for p in 1 2; 
do 
   mkdir -p "/tmp/tt/tt${p}"; 
   for t in 1 2; 
   do 
      touch "/tmp/tt/tt${p}/test${t}"
   done
done

I am using the following script:

declare -A sourceDirTree
create_source_directory_tree()
{        
      
   root_dir=$1
   
   j=1
   while read dir;
   do    
      declare -a siteFiles$j
      dir=${dir##*/}
      i=1   
      while read file;
      do 
         declare -A arrVar$j$i
         declare -A "arrVar$j$i[path]=$file"
         declare -a "siteFiles$j+=(arrVar$j$i)"
         ((i++))
      done <<< $(find ${root_dir}/${dir} -type f)
      arr=siteFiles$j
      for index in "${arr[@]}"
      do 
         declare -n temp="$index"
         echo "${temp[path]}"
      done
      sourceDirTree[$dir]="siteFiles$j"
      ((j++))
   done <<< $(find ${root_dir} -type d -maxdepth 1 -mindepth 1 2> /dev/null)  
} 

create_source_directory_tree /tmp/tt

the result I am getting is the following:

# ./test.sh 
siteFiles1 arrVar11
siteFiles2 arrVar21

and I am not getting why? Could you please help me?

going more in details, the following example works:

declare -A sourceDirTree
create_source_directory_tree()
{        
      
   dir="/tmp/tt/tt1"
   
   declare -a siteFiles
   dir=${dir##*/}
   i=1   
   while read file;
   do
      echo "Processing file $file" 
      declare -A as$i
      declare -A "as$i[path]=$file"
      declare -a "siteFiles+=(as$i)"
      ((i++))
   done <<< $(find /tmp/tt/${dir} -type f)
   for index in "${siteFiles[@]}"
   do 
      declare -n temp="$index"
      echo "${temp[path]}"
   done
}

but the following does not work:

declare -A sourceDirTree
create_source_directory_tree()
{        
      
   dir="/tmp/tt/tt1"
   
   j=1
   declare -a siteFiles$j
   dir=${dir##*/}
   i=1   
   while read file;
   do
      echo "Processing file $file" 
      declare -A as$i
      declare -A "as$i[path]=$file"
      declare -a "siteFiles$j+=(as$i)"
      ((i++))
   done <<< $(find /tmp/tt/${dir} -type f)
   arr=siteFiles$j
   for index in "${arr[@]}"
   do 
      declare -n temp="$index"
      echo "${temp[path]}"
   done
}

it gives me the following output:

Processing file /tmp/tt/tt1/test1
Processing file /tmp/tt/tt1/test2
as1
2

There are 2 best solutions below

7
tjm3772 On

sup[arr]=$arr is the same thing as sup[arr]=$arr[0]. You're only getting the first element of the array with that assignment. Bash's data structures in general are not that powerful. Arrays only map integers to strings, and associative arrays only map strings to strings. You can't nest data structures inside each other without resorting to hacks.

In this case you could store the name of the array in sup and use a name reference as you've done in other places.

sup[arr]=arr
# iterating items instead of indices here, if you really
# need the indices then use the ${!sup[@]} logic as you have 
for el in "${sup[@]}" ; do
  declare -n items="$el"
  for item in "${items[@]}" ; do
    declare -n temp="$item"
    echo "${temp[file]}"
  done
done
0
learning-man On

I think the solution is the following:

arr=siteFiles$j[@]
for index in "${!arr}"
do
   declare -n temp="$index"
   echo "${temp[path]}"
done