3

I have a problem with using array as parameter in function.

#!/usr/bin/env bash

function array_param
{
  local ARRAY_s; local ARRAY_t; local OPTIND

  while getopts 's:t:' opt ; do
    case "$opt" in
      s) ARRAY_s=$OPTARG;;
      t) ARRAY_t=$OPTARG;;      
    esac
  done
  shift $((OPTIND-1))
  echo "ARRAY_s=${ARRAY_s[@]}; ARRAY_t=${ARRAY_t[@]}"
}

array_s=(100 200 300)
array_t=(0 10 3585)

array_param -s ${array_s} -t ${array_t}

Why is only the first element assigned to variables ARRAY_s and ARRAY_t?

Result: ARRAY_s=100; ARRAY_t=0

3
  • ${array_s} is the first element of the array. Try "${array_s[@]}" Commented Jan 12, 2018 at 13:29
  • 1
    ARRAY_s=$OPTARG is also only a string assignment, not an array assignment. What are you trying to do exactly? Copy arrays following the parameters to ARRAY_s and ARRAY_t? Commented Jan 12, 2018 at 13:31
  • Yes, I try to assign the -s and -t parameters to a variable and use it in a function (I only inserted a fragment that I can't solve). Commented Jan 12, 2018 at 13:40

3 Answers 3

1

modifying slightly function (using lowercase for variable, and using array semantics)

array_param() {
    local l_array_s l_array_t OPTIND

    while getopts 's:t:' opt ; do
        case "$opt" in
        s) l_array_s+=( "$OPTARG" ) ;;
        t) l_array_t+=( "$OPTARG" ) ;;
        esac
    done
    shift $((OPTIND-1))
    echo "l_array_s=${l_array_s[*]}; l_array_t=${l_array_t[*]}"
}

can be called

array_param "${array_s[@]/#/-s}" "${array_t[@]/#/-t}"
  • ${array_s[@]/#/-s} notation is specificc to bash, # matches start of string and is replaced by -s for each element in array.

following printf to understand how arguments are passed

printf "<%s> " "${array_s[@]/#/-s}" "${array_t[@]/#/-t}"

also compare

printf "<%s> " "${array_s}"
printf "<%s> " "${array_s[@]}"
printf "<%s> " "${array_s[*]}"
Sign up to request clarification or add additional context in comments.

2 Comments

You are missing quotes "$OPTARG". Otherwise, interesting use of /#/-s...+1.
@PesaThe, true, fixed
0

${array_s} is equivalent to ${array_s[0]}, that's why only the first element is assigned:

#!/usr/bin/env bash

array_param() {   
    local opt OPTIND tmp
    local -a arr_s arr_t

    while getopts 's:t:' opt; do
        case $opt in
            s) tmp=$OPTARG[@]; arr_s=("${!tmp}") ;;
            t) tmp=$OPTARG[@]; arr_t=("${!tmp}") ;;
        esac
    done
    echo "arr_s = ${arr_s[*]}"
    echo "arr_t = ${arr_t[*]}"
}

arr1=(100 200 300)
arr2=(0 10 3585)

array_param -s arr1 -t arr2
  • local opt: you should localize all variables, even opt
  • tmp=$OPTARG[@]: creates a tepmporary variable of this format: array_name[@]
  • arr=(values): array assignment
  • ${!tmp}: variable indirection. It first expands to the value of $tmp, and then expands once more to the final result: ${!tmp} -> ${array_name[@]} -> all values

You can also use nameref (makes the code more readable but requires bash 4.3 or later):

s) local -n tmp=$OPTARG; arr_s=("${tmp[@]}") ;;
t) local -n tmp=$OPTARG; arr_t=("${tmp[@]}") ;;

Comments

0

You can't pass array_s and array_t as array, getopts will get only first element of each array.

But, you can try to use C-style for loop like that to increment local ARRAY_s and ARRAY_t variable, print them in the end:

    $ cat optarg.sh 
    #!/usr/bin/env bash

    function array_param
    {
      local OPTIND

      while getopts 's:t:' opt ; do
        case "$opt" in
            s) ARRAY_s+=("${OPTARG}");;
            t) ARRAY_t+=("${OPTARG}");;      
        esac
      done
      shift $((OPTIND-1))
    }

    array_s=(100 200 300)
    array_t=(0 10 3585)

    #Works if only array_s length equal array_t length.
    for ((args=0; args<${#array_s[@]}; args++))
    do
        array_param -s ${array_s[args]} -t ${array_t[args]}
    done

    echo "ARRAY_s=${ARRAY_s[@]}; ARRAY_t=${ARRAY_t[@]}"

Output:

ARRAY_s=100 200 300; ARRAY_t=0 10 3585

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.