Передача нескольких различных массивов в функцию оболочки

Поскольку оболочки, отличные от ksh, не поддерживают передачу по ссылке, как несколько массивов могут быть переданы в функцию в bash без использования глобальных переменных и таким образом, чтобы любое содержимое допустимой переменной можно было включить в качестве элемента массива (не зарезервировано сигилы)?

Ответы на вопрос(2)

declare -a a=( "aa bb" 123 '$ $ 

Выход:

a before sub:
'aa bb'
'123'
'$ $  )
declare -a b=( "bb cc" 456 '###' )

printf "\n%s\n" 'a before sub:'
printf "'%s'\n" "${a[@]}"
printf "\n%s\n" 'b after sub:'
printf "'%s'\n" "${b[@]}"


sub ()
{
  eval a0=\${$1[0]}                     # get value a[0]
  eval b1=\${$2[1]}                     # get value b[1]
  echo "a[0] = '$a0'"
  echo "b[1] = '$b1'"

  eval $1[0]='a---a'                    # set value a[0]
  eval $2[1]=999                        # set value b[1]

} # ----------  end of function sub  ----------

sub a b     # call function sub

printf "\n%s\n" 'a after sub:'
printf "'%s'\n" "${a[@]}"
printf "\n%s\n" 'b after sub:'
printf "'%s'\n" "${b[@]}"

Выход:

a before sub:
'aa bb'
'123'
'$ $ $'

b after sub:
'bb cc'
'456'
'###'
a[0] = 'aa bb'
b[1] = '456'

a after sub:
'a---a'
'123'
'$ $ $'

b after sub:
'bb cc'
'999'
'###'
b after sub: 'bb cc' '456' '###' a[0] = 'aa bb' b[1] = '456' a after sub: 'a---a' '123' '$ $ ) declare -a b=( "bb cc" 456 '###' ) printf "\n%s\n" 'a before sub:' printf "'%s'\n" "${a[@]}" printf "\n%s\n" 'b after sub:' printf "'%s'\n" "${b[@]}" sub () { eval a0=\${$1[0]} # get value a[0] eval b1=\${$2[1]} # get value b[1] echo "a[0] = '$a0'" echo "b[1] = '$b1'" eval $1[0]='a---a' # set value a[0] eval $2[1]=999 # set value b[1] } # ---------- end of function sub ---------- sub a b # call function sub printf "\n%s\n" 'a after sub:' printf "'%s'\n" "${a[@]}" printf "\n%s\n" 'b after sub:' printf "'%s'\n" "${b[@]}"

Выход:

a before sub:
'aa bb'
'123'
'$ $ $'

b after sub:
'bb cc'
'456'
'###'
a[0] = 'aa bb'
b[1] = '456'

a after sub:
'a---a'
'123'
'$ $ $'

b after sub:
'bb cc'
'999'
'###'
b after sub: 'bb cc' '999' '###' ) declare -a b=( "bb cc" 456 '###' ) printf "\n%s\n" 'a before sub:' printf "'%s'\n" "${a[@]}" printf "\n%s\n" 'b after sub:' printf "'%s'\n" "${b[@]}" sub () { eval a0=\${$1[0]} # get value a[0] eval b1=\${$2[1]} # get value b[1] echo "a[0] = '$a0'" echo "b[1] = '$b1'" eval $1[0]='a---a' # set value a[0] eval $2[1]=999 # set value b[1] } # ---------- end of function sub ---------- sub a b # call function sub printf "\n%s\n" 'a after sub:' printf "'%s'\n" "${a[@]}" printf "\n%s\n" 'b after sub:' printf "'%s'\n" "${b[@]}"

Выход:

a before sub:
'aa bb'
'123'
'$ $ $'

b after sub:
'bb cc'
'456'
'###'
a[0] = 'aa bb'
b[1] = '456'

a after sub:
'a---a'
'123'
'$ $ $'

b after sub:
'bb cc'
'999'
'###'
 Charles Duffy08 июн. 2012 г., 22:00
Чтобы быть в безопасности, это должно быть использованиеprintf %q цитировать, а не предполагать, чтоprintf "'%s'" будет в безопасности. Увидетьmywiki.wooledge.org/BashFAQ/048 для обсуждения вопросов безопасности вокруг eval.
 Charles Duffy01 дек. 2017 г., 16:49
В качестве конкретного примера рассмотримdeclare -a a=( $'\'$(touch /tmp/i-could-have-been-rm-rf-~)\'' ) - Вы не хотитеprintf сделать это''$(touch /tmp/i-could-have-been-rm-rf-~)''таким образом, что кавычки внутри данных отменяют те, которые добавленыprintf.
Решение Вопроса
Since bash 4.3

современный bash поддерживает передачу по ссылке (a.k.anameref атрибут) как:

demo_multiple_arrays() {
  local -n _array_one=$1
  local -n _array_two=$2
  printf '1: %q\n' "${_array_one[@]}"
  printf '2: %q\n' "${_array_two[@]}"
}

array_one=( "one argument" "another argument" )
array_two=( "array two part one" "array two part two" )

demo_multiple_arrays array_one array_two

Смотрите такжеdeclare -n в справочной странице.

Before bash 4.3

Это можно сделать безопасно, используя соглашение о вызовах, которое ставит число аргументов перед каждым массивом, как таковое:

demo_multiple_arrays() {
  declare -i num_args array_num;
  declare -a curr_args;
  while (( $# )) ; do
    curr_args=( )
    num_args=$1; shift
    while (( num_args-- > 0 )) ; do
      curr_args+=( "$1" ); shift
    done
    printf "$((++array_num)): %q\n" "${curr_args[@]}"
  done
}

Это можно затем назвать следующим образом:

array_one=( "one argument" "another argument" )
array_two=( "array two part one" "array two part two" )
demo_multiple_arrays \
  "${#array_one[@]}" "${array_one[@]}" \
  "${#array_two[@]}" "${array_two[@]}"

Ваш ответ на вопрос