3

I have a function to show index of chosen element. I'm trying to pass a parameter to function to use it as an array name. This works:

getIndex() {
arrname=$1[@]
b=("${!arrname}")
index=1; while ((index<${#b[@]})); do
    if [[ "${b[$index]}" = "$VALUE" ]]; then
        echo "index is $index"; return
    fi  
        ((index++)); done

}

But the array, whose name I pass to this function, has index 1 as index of first element (I need this to have indexes similar to line numbers, from which I get patterns in the array:

a=1
while read line; do
    if [[ $line =~ ^[0-9] ]]; then
        avg[$a]=`echo $line | awk '{print $6}'`
        ((a++));    
    fi

And if I'm running function getIndex() the first element of the array starts from index 0.

So, the question is: Is there any way to pass array name in parameter to function with saving indexes of array? Or maybe I just need to forget about it and add +1 to function answer.

1

You are using this construction:

b=("${!arrname}")

This expands the values of the array, creating a new array b[] with the bash default array indexes starting from 0. To properly initialise a copy of the array you would need to restore the indexes (e.g. by parsing or eval-ing the output of declare -p arrname)

Rather than making a copy, a better approach is to expand the indexes rather than the values, and iterate over the array using those. This approach will work with sparse, or non-zero based standard arrays (and even bash4 associative arrays).

The catch (isn't there always) is that the ! is pulling double duty: its use in indirection ${!name} is not compatible with its use for expanding array indexes ${!arrname[@]}, so we have to use eval.

Here's a modified version which implements this:

getIndex2() {
  local arrname=$1 iidx idxs index ival val
  printf -v iidx '"${!%s[@]}"' "$arrname"
  eval "idxs=($iidx)"
  for index in "${idxs[@]}"; do
    printf -v ival '${%s[%s]}' "$arrname" "$index"
    eval "val=$ival"
    if [[ "${val}" = "$VALUE" ]]; then
        echo "index is $index"; return   
    fi
  done
}

Note the use of printf -v var ... (bash-3.1+) to try to keep the eval readable. The indexes are expanded into an array, this is not strictly necessary, a flat list would do also.

See also BashFAQ/006.

1

Arrays in Bash are zero-based. They just are. That said, if you know that the array is always going to be indexed by numbers starting from 1, just add +1 to the result. Add a second argument to the function, that will tell it what number to start from or add to the result, and add a sensible default for cases where the second argument is missing. Or loop over indices as mr.spuratic suggests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.