Como expandir o conteúdo da matriz de seu nome? [duplicado]

1

Eu tenho uma matriz

declare -a arr0=("'1 2 3'" "'4 5 6'")

e uma variável

x=0

Então eu crio a nova variável com o nome da matriz

tmp="arr$x"

e gostaria de poder expandir arr0 conteúdo desta variável tmp como esta

newArr=( "${!tmp}" )

e para usar newArr como o array comum, e. usar índices etc.

Mas quando eu tento imprimir agora, é assim:

$ echo ${newArr[@]}
'1 2 3'

Apenas o primeiro elemento é armazenado e não sei como corrigi-lo.

Eu também tentei criar newArr como este

newArr=( "${!tmp[@]}" )

mas depois é ainda pior - apenas 0 é impresso.

$ echo ${newArr[@]}
0

Então, você sabe, como usar uma matriz se o nome dela estiver armazenado em alguma outra variável?

    
por Eenoku 08.03.2017 / 12:44

3 respostas

3

É possível com eval :

$ declare -a array=( 1 2 3 4 )
$ echo "${array[@]}"
1 2 3 4
$ p=ay
$ tmp=arr$p
$ echo "$tmp"
array
$ echo "\${${tmp}[@]}"
${array[@]}
$ echo "newarray=(\"\${${tmp}[@]}\")"
newarray=("${array[@]}")
$ eval "newarray=(\"\${${tmp}[@]}\")"
$ echo "${newarray[@]}"
1 2 3 4
$

Comandos que começam com echo são para ilustração, eval é perigoso.

Observe que o acima não preserva os índices da matriz para matrizes esparsas.

    
por 08.03.2017 / 14:30
1

A expansão indireta tem algumas exceções e usa! em matrizes é uma das exceções.

Do homem bash:

If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion.

The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. ${!prefix*} Names matching prefix. Expands to the names of variables whose names begin with prefix, separated by the first character of the IFS special variable.

Conforme descrito em BASH FAQ06 , uma solução alternativa é a seguinte:

arrA=("AA" "2" "4")
echo -e "array arrA contains: \c" && declare -p arrA
ref=arrA;
tmp=${ref}[@] #this can be adjusted to [1] , [2] etc to refer to particular array items
echo "Indirect Expansion Printing: ${!tmp}"

#Output
array arrA contains: declare -a arrA='([0]="AA" [1]="2" [2]="4")'
Indirect Expansion Printing: AA 2 4
    
por 08.03.2017 / 16:28
1

bash 4.3 adicionou suporte para ksh93 -like namerefs.

Então, no bash-4.3 ou acima, você pode fazer:

a0[5]=whatever
x=0
typeset -n var="a$x"
printf '%s\n' "${var[5]}"

Mas note que é uma referência (um ponteiro, não uma cópia) para a variável nome , não a variável (a diferença é importante quando você tem várias variáveis pelo mesmo nome em contextos diferentes, como para variáveis locais em funções).

bash copied ksh arrays com seu design estranho. Fazer uma cópia de uma matriz em bash é difícil, você pode usar uma função auxiliar como:

copy_array() { # Args: <src_array_name> <dst_array_name>
  eval '
    local i
    '"$2"'=()
    for i in "${!'"$1"'[@]}"; do
      '"$2"'[$i]=${'"$1"'[$i]}
    done'
}

Para ser usado, por exemplo, como:

$ a0[5]=123
$ x=0
$ copy_array "a$x" var
$ typeset -p var
declare -a var=([5]="123")

ksh (e bash que copiou ksh ) é o único shell onde as matrizes são esparsas (ou são matrizes associativas cujas chaves são limitadas a inteiros positivos) (também as únicas matrizes com índices começando em 0 em vez de 1, ou onde $array não intuitivamente não se expande para os elementos, mas o elemento de indice 0). É muito mais fácil com outras camadas.

  • rc : array_copy = $array
  • fish : set array_copy = $array
  • csh : set array_copy = ($array:q)
  • zsh ou yash : array_copy=("${array[@]}"}

Para cópia indireta (em que $var contém o nome da matriz de origem):

  • rc : eval array_copy = '$'$var
  • fish : eval set array_copy \$$var
  • csh : eval "set array_copy = (\$${var}:q)"
  • zsh : array_copy=("${(@P)var}")
  • yash (ou zsh ): eval 'array_copy=("${'"$var"'[@]}")'
por 08.03.2017 / 16:33