Como acessar mais membros de uma matriz ao usar indireção de variável bash?

2

Considere o seguinte exemplo, parece que está funcionando bem com o índice 0 :

$ a1=(1 2 3)
$ a2=(a b c)
$ for x in a1 a2; do echo "${!x}"; done
1
a
$ for x in a1 a2; do echo "${!x[0]}"; done
1
a

No entanto, com o índice 1 , não imprime nada:

$ for x in a1 a2; do echo "${!x[1]}"; done    

As matrizes por si só são boas:

$ echo "${a1[1]} ${a2[1]}"
2 b

Editar - Um caso de uso real baseado na ilkkachu resposta

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

typeset -n x
for x in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
  url="${x[0]}" app="${x[1]}" ext="${x[2]}"
  [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
  tar -xf "./${app}${ext}"
  cd "./${app}" && ./configure && make -j2 && make install && ldconfig
  cd ..
done
    
por NarūnasK 04.09.2018 / 22:03

2 respostas

6

"${!x[1]}" é uma referência indireta usando o elemento no índice 1 da matriz x .

$ foo=123; bar=456; x=(foo bar); echo "${!x[1]}"
456

Nas versões atuais do Bash (4.3 e acima), você pode usar namerefs para obter o que deseja:

$ a=(00 11 22 33 44)
$ typeset -n y=a
$ echo "${y[3]}"
33

ou seja, com o nameref configurado, "${y[3]}" é uma referência ao elemento 3 na matriz denominada por y .

Para repetir os arrays como você faz na sua pergunta, basta criar x a nameref.

a1=(1 2 3); a2=(a b c)
typeset -n x;
for x in a1 a2; do
    echo "${x[1]}"
done

As atribuições feitas pelo loop for alteram o valor de x em si (mudando para o que a referência aponta). Uma atribuição regular ( x=123 ou x[1]=123 ) altera a variável atualmente referenciada por x . Então, isso mudaria os dois a1[1] e a2[1] para foo :

typeset -n x;
for x in a1 a2; do
    x[1]=foo
done

O motivo "${!x[0]}" parece funcionar é que x e x[0] são equivalentes. Se você tivesse echo "${x[0]}" dentro de seu loop (sem o estrondo), você obteria a1 , a2 , o mesmo que com echo "$x" .

    
por 04.09.2018 / 22:54
0

O Indirection funciona expandindo um valor e, em seguida, usando o resultado da expansão como o novo nome de uma variável:

$ a=abc; x=a; echo "${!x}"
abc

$ a=(one two three four); x=a[0]; y=a[1]; z=a[3]; echo "${!x}   ${!y}   ${!z}"
one   two   four

Então, para o seu exemplo:

$ a1=(1 2 3);   a2=(a b c)
$ for x in a1[0] a2[0] a1[1] a1[2]; do echo "${!x}"; done
1
a
2
b

Para o seu "caso de uso da vida real", você pode fazer:

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

for s in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
    x=${s}[0] y=${s}[1] z=${s}[2]
    url="${!x}" app="${!y}" ext="${!z}"
    [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
    tar -xf "./${app}${ext}"
    cd "./${app}" && ./configure && make -j2 && make install && ldconfig
    cd ..
done
    
por 15.10.2018 / 22:03