Work-Around para armazenar valores de matriz em uma variável de ambiente, em seguida, chamando do script Bash

3

Procurei uma resposta para a pergunta "Posso usar uma matriz como uma variável de ambiente e depois chamá-la de um script de shell Bash" e cheguei à conclusão de que ela não era "oficialmente" suportada como (delineada aqui e aqui ).

No entanto, eu realmente tive a necessidade de fazer isso e criei um "trabalho por aí" e queria ter suas opiniões.

Configuração: criei uma variável no meu arquivo .profile semelhante a:

HOST_NAMES='server1 server2 server3'

Então, no início do meu script de shell, escrevi:

SRVR_ARRAY=($(echo $HOST_NAMES | awk '{for (i = 1; i <=NF; i++) print $i " "}'))

Mais tarde, no script, quando chegou a hora de fazer algum trabalho, liguei para:

for h in "${SRVR_ARRAY[@]}"; do
ping $h
done

E funcionou! Agora eu tenho certeza que este é Bash shell scripting jerry-riggin no seu melhor, mas queria ver se alguém poderia ver quaisquer riscos neste uso?

    
por JuanD 23.03.2017 / 05:38

2 respostas

3

Os problemas que você pode enfrentar são os mais comuns: divisão e globbing.

Você não pode ter strings com espaço em branco, pois elas serão divididas em itens de matriz separados e qualquer coisa que se pareça com um caractere glob ( *?[] ) será expandida para nomes de arquivos correspondentes. Provavelmente não é um problema com nomes de host, mas, em geral, é.

Este é um problema comum, discutido repetidamente, ver, e. Expansão de uma concha variável e efeito da glob e dividida nela e

Para contornar isso, você precisaria a) definir IFS para algo diferente de espaço em branco e separar suas strings com isso eb) desabilitar a globbing com set -f .

Isso usaria | como separador e dividiria a string. Você poderia usar qualquer caractere não necessário nos valores, talvez até mesmo algum caractere de controle como $'HOST_NAMES1'1 (Use awk no Bash para criá-lo).

#!/bin/bash
string='foo|bar'
IFS='|'; set -f
array=($string)        # split it

IFS='|'
string="${array[*]}"   # merge it back together

Além disso, como dizem nos comentários, se sua variável tem apenas nomes de host e você está bem com a divisão no espaço em branco, você não precisa do awk para dividi-lo. O shell fará isso ao atribuir um array ou iniciar o loop:

SRVR_ARRAY=( $HOST_NAMES )
for x in $HOST_NAMES ; do ...

(Novamente, você terá problemas se $() contiver caracteres glob.)

Na verdade, é isso que vai acontecer mesmo com o seu exemplo: %code% imprime algo, o shell captura, divide em palavras, pois o %code% não estava entre aspas duplas e, em seguida, salva as palavras separadamente na matriz.

    
por 23.03.2017 / 11:43
0

Você pode armazenar a saída de declare -p na variável de ambiente:

array=(foo 'bar baz'); array[12]=sparse
export ARRAY_definition="$(declare -p array)"

Em seguida, no script bash executado:

eval "$ARRAY_definition"

Note que é importante que o eval seja executado na mesma localidade que o declare one (e, de preferência, a mesma versão de bash )

Se o eval não for executado no escopo global, a matriz será declarada local .

Com zsh , você pode usar a citação para evitar ter que usar esse perigoso eval :

export ARRAY_definition=${(j: :)${(q)array}}

import com:

array=(${(Q)${(z)ARRAY_definition}})

Como alternativa, você pode usar um shell como rc , es ou fish que suporta exportação de matrizes nativamente (usando sua própria codificação).

    
por 06.04.2017 / 17:01