algalg
algalg

Reputation: 821

Bash: Removing empty or missing entries in associative array

I have an associative array, as below, with helpful suggestions from Stackoverflow community to build the arrays and have them behave in the order values are defined. i.e. Disks go into 'disks_order' in the order they are defined.

Everything is working well, until we encounter something that we don't expect. For example, if an entry is empty (noticed the line commented out). This throws everything out:

#!/bin/bash

localEndPoint="/tmp/test/"

declare -A disks

 disks=([0-UUID]=a6506a2c844b40cc [0-MountPoint]='/media/user/SomePath/')
disks+=([1-UUID]=a1f369ab35c5a22e [1-MountPoint]='/media/user/SomeOtherPath/')
disks+=([2-UUID]=6fd9ad56f4b94648 [2-MountPoint]='/media/user/AnotherOne/')
##disks+=([3-UUID]=aae8222d2ac131b0 [3-MountPoint]='/media/user/YetAnother/')  ## notice this line is commented out
disks+=([4-UUID]=0 [4-MountPoint]='/home/user/')
disks+=([5-UUID]=0 [5-MountPoint]='/home/user2/')


# build array so as to reflect the way it was defined above
# find total number of keys used and then use that for the division calculation (https://stackoverflow.com/questions/63532910)
declare -A keycount; for i in "${!disks[@]}"; do keycount[${i//[0-9]-/}]=""; done
totalDisks=$((${#disks[*]} / ${#keycount[@]}))
x=1; while [[ $x -le $totalDisks ]]; do disks_order+="$(( x-1 )) "; x=$(( $x + 1 )); done # 'disks_order' array is used to process which disks are handled in what order

# list everything
for i in ${disks_order[*]}; do
    diskLabel=$( basename "${disks[$i-MountPoint]}" )
    printf "Point $(( i+1 ))"
        if [[ "${disks[$i-UUID]}" == 0 ]]; then
            printf ": Path "
        else
            printf ": Disk "
        fi
    printf "${disks[$i-MountPoint]} to ${localEndPoint}${diskLabel}/\n"
done

Actual output

Point 1: Disk /media/user/SomePath/ to /tmp/test/SomePath/
Point 2: Disk /media/user/SomeOtherPath/ to /tmp/test/SomeOtherPath/
Point 3: Disk /media/user/AnotherOne/ to /tmp/test/AnotherOne/
Point 4: Disk  to /tmp/test//
Point 5: Path /home/user/ to /tmp/test/user/

(notice the empty line for Point 4, and loss of /home/user2)

Desired Output

Point 1: Disk /media/user/SomePath/ to /tmp/test/SomePath/
Point 2: Disk /media/user/SomeOtherPath/ to /tmp/test/SomeOtherPath/
Point 3: Disk /media/user/AnotherOne/ to /tmp/test/AnotherOne/
Point 4: Path /home/user/ to /tmp/test/user/
Point 5: Path /home/user2/ to /tmp/test/user2/

So. How can I remove empty entries disks_order?

I suspect we need to revisit the solution from this answer re "counting the total number of keys in an array"?

i.e.

declare -A keycount; for i in "${!disks[@]}"; do keycount[${i//[0-9]-/}]=""; done
totalDisks=$((${#disks[*]} / ${#keycount[@]}))
x=1; while [[ $x -le $totalDisks ]]; do disks_order+="$(( x-1 )) "; x=$(( $x + 1 )); done

Edit: totalDisks is needed to display total number of entries in array, to be used later in the script.

Upvotes: 0

Views: 211

Answers (1)

KamilCuk
KamilCuk

Reputation: 141165

Add a function to add discs that would number them auto....

declare -A disks
disks_add() {
   local n="$((${#disks[@]}/2))"
   disks+=([$n-UUID]="$1" [$n-MountPoint]="$2")
}
disks_add a6506a2c844b40cc '/media/user/SomePath/'

Remember to check your scripts with https://shellcheck.net

But I do not see any advantages in your design, just you add complexity with those totalDisks and disk_order stuff. I would just use two arrays:

disk_uuids=() disk_mountpoints=()
add_disk() { 
   # I am so lazy to type...
   disk_uuids+=("$1") 
   disk_mountpoints+=("$2")
}
add_disk a6506a2c844b40cc '/media/user/SomePath/'
# Who cares about indexes??
add_disk a1f369ab35c5a22e '/media/user/SomeOtherPath/'
add_disk 6fd9ad56f4b94648 '/media/user/AnotherOne/'

for ((i=0;i<${#disk_uuids[@]};++i)); do
    echo "Wow, so easy no sorting..."
    printf "%s\t%s\t%s\n" "$i" "${disk_uuids[i]}" "${disk_mountpoints[i]}"
done

Upvotes: 1

Related Questions