Eu tenho um script de shell bastante complexo que processa várias listas de valores que são lidos de um arquivo como valores separados por espaço, por exemplo
SET1="value1 value2 value3"
for i in ${SET1}; do
...
Agora quero criar uma lista formatada de forma semelhante no script para escrever. No entanto, se eu fizer (por exemplo) isso:
DISCOVERED=''
DISCOVERED+=( us-east-1 )
DISCOVERED+=( us-east-2 )
DISCOVERED+=( us-west-1 )
for REGION in ${DISCOVERED} ; do
echo $REGION
done
Eu não recebo nenhuma saída. Eu recebo saída se eu especificar in ${DISCOVERED[@]}
. Parece que estou trabalhando com diferentes tipos de dados em SET1 e DISCOVERED.
Posso anexar facilmente a uma string com valores separados por espaço, mas acabo com um espaço inicial ou final que precisa ser limpo:
function append_discovered {
local VALUE="$1"
if [ -z "${DISCOVERED}" ] ; then
DISCOVERED="$VALUE"
else
DISCOVERED="${DISCOVERED} ${VALUE}"
fi
}
.... mas isso parece bastante complicado.
Eu poderia tratar minha variável de saída como uma matriz - mas preciso convertê-la de volta ( DISCOVERED="${DISCOVERED[@]}"
) em locais apropriados para usar uma construção diferente para iterar por meio desta lista do que para as outras listas.
Qual é o tipo de dados para meus dados de entrada (por exemplo, $SET1 acima) se não for um array?
Existe uma maneira mais simples de anexar esta lista e manter o mesmo tipo de dados?
De fato.
SET1
é uma corda. Acontece que você interpreta o valor da string como sendo vários elementos separados por espaço.DISCOVERED
por outro lado é um array com vários elementos.Um problema com o seu
SET1
código no topo da sua pergunta é que cada elemento será globalizado e expandido. Portanto, se você tiver um arquivo chamadoonebananatwo
em seu diretório atual e encontrar um elementoone*
, o globbing se expandiráone*
para se tornaronebananatwo
. (Evitar isso é o motivo pelo qual as variáveis de aspas duplas são sempre altamente recomendadas.)Você pode usar uma expansão condicional para inserir o espaço somente se a string não estiver vazia:
(Observe que removi a palavra-
function
chave não padrão e coloquei os nomes das variáveis em letras minúsculas para que não entrem em conflito inesperado com as variáveis reservadas.)Aqui está o que está acontecendo com
$discovered${discovered:+ }$value
:$discovered
é a string vazia,${discovered:+ }
também retorna uma string vazia e, portanto, o resultado é apenas$value
$discovered
tem um valor,${discovered:+ }
retorna um espaço e, portanto, o resultado é uma string composta$discovered
e$value
separada por um único espaçoNo futuro, recomendo que você considere o uso de uma matriz para tipos de dados de matriz em vez de elementos separados por espaço em uma string, mas entendo que adaptar isso a um script existente pode não ser econômico ou sensato.
No bash 5.x do meu Mac, sua primeira sintaxe funciona:
A saída é:
Talvez você esperasse que a
DISCOVERED=''
instrução excluísse todos os elementos da matriz em vez de definir o primeiro elemento como uma string vazia, então suas tentativas de expandir/retornar o primeiro elemento da matriz fizeram parecer que a matriz estava vazia?Se você quiser garantir que a variável da matriz seja limpa (sem elementos), sugiro
DISCOVERED=()
ouunset DISCOVERED
.Editado para adicionar:
Para gerar uma string delimitada a partir dos elementos da matriz, geralmente uso um simples de duas linhas. Este exemplo usa '
:
' como caractere delimitador:(Não incluí o primeiro elemento vazio da matriz) A saída:
Ele usa uma propriedade do built-in
printf
para iterar os elementos da matriz, acrescentando o delimitador a cada um. (Viva, não preciso escrever um loop!) A segunda linha remove o delimitador final. Isso também funcionará com o caractere de espaço como delimitador, mas é mais fácil fazê-lo comoSET1="${DISCOVERED[@]}"
. Não é muito elegante ter a segunda linha para retirar o último delimitador, mas funciona para muitos casos de uso, é simples, rápido e não chama comandos externos.