Carles Ràfols
Carles Ràfols

Reputation: 87

Loop over indices of sliced array in bash

I want to loop over the indices of an array starting on the second index. How can I do this?

I have tried:

myarray=( "test1" "test2" "test3" "test4")
for i in ${!myarray[@]:1}
do
    # I only print the indices to simplify the example
    echo $i 
done

But doesn't work.

Obviously this works:

myarray=( "test1" "test2" "test3" "test4")
myindices=("${!myarray[@]}")
for i in ${myindices[@]:1}
do
    echo $i
done

But I would like to combine everything in the for loop statement if possible.

Upvotes: 4

Views: 1812

Answers (2)

agc
agc

Reputation: 8416

Use the # parameter length expansion:

myarray=( "test1" "test2" "test3" "test4")
for (( i=1;  i < ${#myarray[@]};  i++ ))
do
    # only print the indices to simplify the example
    echo $i 
done

Note that the ! indirect expansion operator is evidently not compatible with substring expansion since:

echo "${!myarray[@]:2}"

Produces an error code 1 and outputs to STDERR:

bash: test1 test2 test3 test4: bad substitution

At least for current versions of bash, v.4.4 and earlier. Unfortunately man bash doesn't make it sufficiently clear that substring expansion doesn't work with indirect expansion.

Upvotes: 3

L&#233;a Gris
L&#233;a Gris

Reputation: 19625

I'd do it this way:

#!/usr/bin/env bash

myarray=('a' 'b' 'c' 'd')

start_index=2
# generate a null delimited list of indexes
printf '%s\0' "${!myarray[@]}" |
  # slice the indexes list 2nd entry to last
  cut --zero-terminated --delimiter='' --fields="${start_index}-" |
  # iterate the sliced indexes list
  while read -r -d '' i; do
    echo "$i"
  done

Output does not list first index 0 as expected:

1
2
3

Works as well with an associative array:

#!/usr/bin/env bash

typeset -A myassocarray=(["foo"]='a' ["bar"]='b' ["baz"]='c' ["qux"]='d')

start_index=2
# generate a null delimited list of indexes
printf '%s\0' "${!myassocarray[@]}" |
  # slice the indexes list 2nd entry to last
  cut --zero-terminated --delimiter='' --fields="${start_index}-" |
  # iterate the sliced indexes list
  while read -r -d '' k; do
    echo "$k"
  done

Output:

bar
baz
qux

Upvotes: 1

Related Questions