Differences between revisions 1 and 2
Revision 1 as of 2018-03-14 19:44:27
Size: 1564
Editor: GreyCat
Comment: How do I print an array in reverse order?
Revision 2 as of 2018-04-07 22:30:02
Size: 1978
Editor: c-68-54-93-130
Comment: Mentioned BASH_ARGV. https://dylanaraps.com/2018/02/05/bash-tricks/
Deletions are marked like this. Additions are marked like this.
Line 35: Line 35:

When the array is to be passed to a function or when `extdebug` is already set, `BASH_ARGV` can be used to operate on array items in reverse order. (For most other cases, `BASH_ARGV` may not be as efficient as the examples above.)

{{{
reverse_array()
{
  shopt -s extdebug
  f()
  {
    printf "%s " "${BASH_ARGV[@]}";
  }
  f "$@"
  shopt -u extdebug
}
a=(1 2 3 4)
reverse_array "${a[@]}"
}}}

How do I print an array in reverse order?

First note that the concept of order applies only to indexed arrays, not associative arrays. The answer would be very simple if there were no sparse arrays, but bash's arrays can be sparse (non-sequential indices). So we have to introduce an extra step.

The first thing we need to do is obtain the indices of the array. We can do this with the ${!array[@]} syntax, introduced in bash 3.0. (Prior to bash 3.0, we would have to make a new copy of the entire array; see below.)

Once we have the list of indices, we can iterate over that list in reverse order. Then use the resulting indices, one by one, to reference the original array. Thus:

# bash 3.0 or higher
array=(world [13]=hello)
idx=("${!array[@]}")     # copy of INDICES
for (( i = ${#idx[@]} - 1; i >= 0; i-- )); do
  j=${idx[i]}
  printf "%s " "${array[j]}"
done
echo

In the degenerate case where we know the array isn't sparse, we could simply iterate over the original array backwards, starting at index length - 1 and simply assuming that this is the last index.

If we need to print a (sparse) array in reverse in bash older than 3.0, then we can copy the entire array in order to remove the sparseness, and then iterate over the copy:

# bash 2.0 or higher; less efficient
array=(world [13]=hello)
tmp=("${array[@]}")      # copy of CONTENTS
i=$(( ${#tmp[@]} - 1 ))
while ((i >= 0)); do
  printf "%s " "${tmp[i]}"
  ((i--))
done
echo

When the array is to be passed to a function or when extdebug is already set, BASH_ARGV can be used to operate on array items in reverse order. (For most other cases, BASH_ARGV may not be as efficient as the examples above.)

reverse_array()
{
  shopt -s extdebug
  f()
  {
    printf "%s " "${BASH_ARGV[@]}";
  }
  f "$@"
  shopt -u extdebug
}
a=(1 2 3 4)
reverse_array "${a[@]}"

BashFAQ/118 (last edited 2019-04-17 19:00:47 by GreyCat)