bash - First indexvalue of sparse array - Stack Overflow

admin2025-04-30  3

I have a sparse array in bash where I don't know the value of the lowest numbered index, and I want to pull that value out with its index. How do I find it?

#/bin/bash

a=( [12]="blue" [31]="violet" [59]="paisley" )

index=?

I want the first one.

I have a sparse array in bash where I don't know the value of the lowest numbered index, and I want to pull that value out with its index. How do I find it?

#/bin/bash

a=( [12]="blue" [31]="violet" [59]="paisley" )

index=?

I want the first one.

Share Improve this question edited Jan 9 at 19:41 akinomyoga 2201 silver badge11 bronze badges asked Jan 6 at 18:29 GrahamGraham 1,75915 silver badges23 bronze badges 3
  • By 'lowest numbered index' do you mean "blue" because it is the first element in the construction of a or because 12<31<59? – dawg Commented Jan 7 at 1:36
  • You need to sort the indices. You can write them to a file and use sort to sort them. Make up your mind whether you need them sorted numerically or alphabetically. – user1934428 Commented Jan 7 at 12:23
  • Do you have to stick with bash? If you can implement your script in zsh, you have sorting of arrays builtin. The sorting methods in zsh are a bit crude, but should be sufficient for your purpose. – user1934428 Commented Jan 7 at 12:25
Add a comment  | 

5 Answers 5

Reset to default 7

Transfer the numerical indices to an array and use its first element:

a=( [59]="paisley" [12]="blue" [31]="violet" )
arr=("${!a[@]}"); echo "${a[${arr[0]}]}"

Output:

blue

Easy. Break a for loop.

#/bin/bash

a=( [12]="blue" [31]="violet" [59]="paisley" )

for index in "${!a[@]}"; do break; done

value="${a[$index]}"

echo "$index - $value"

Another way using read:

a=( [12]="blue" [31]="violet" [59]="paisley" )

read -a ind <<< "${!a[@]}"

echo "$ind"           # will give 12
echo "${ind[0]}"      # will also give 12

echo "${a[ind]}"       # blue

Given this ordinary array:

a=( [12]="blue" [31]="violet" [59]="paisley" )

You can get a return of the integer indices like so:

$ printf "%s\n" "${!a[@]}"
12
31
59

They will be ordered -- if an ordinary indexed array regardless if sparse or not.

Then you can use those indices as you wish.

If you just want the "lowest numbered index" as in the first one that pops out of that array as Bash has sorted them:

$ printf "%s\n" "${!a[@]}" | head -1
12 

BEWARE, however, that Bash associative arrays are unordered and this will not produce the same results.

For an associative array with integer indices, you can sort numerically to get 12 because 12<31<59:

$ printf "%s\n" "${!a[@]}" | sort -n | head -1
12

Then use that as the index back to the original array:

idx=$(printf "%s\n" "${!a[@]}" | sort -n | tail -1) # largest now...
echo "${a[idx]}"                                    # paisley 

With regular arrays sparse or not, you can use the same method without sort.

The following assumes your array is an indexed array, not an associative array, that is, was not declared with declare -A a.

According the source code of GNU bash 5.2 (current stable version), indexed arrays are implemented as sparse doubly-linked lists, the elements are inserted / deleted in numeric order, and ${!a[@]} expands as the sorted list of indexes (numeric order). This is not documented anywhere, so relying on it is a bit dangerous, but if your bash is GNU bash 5.2 (or another version that implements indexed arrays the same way) you can simply try:

index=( ${!a[@]} )
printf 'a[%d] = %s\n' "$index" "${a[index]}"

If you do not know for sure what the order of ${!a[@]} is, or if safety is essential (do not forget that future bash versions could make different choices, e.g. for performance reasons), you can use a for loop to find the minimum index value:

index=( ${!a[@]} )
for n in "${!a[@]}"; do (( index = n < index ? n : index )); done
printf 'a[%d] = %s\n' "$index" "${a[index]}"
转载请注明原文地址:http://anycun.com/QandA/1745951995a91441.html