Loop através de variáveis

13

Estou escrevendo um script bash para usar o rsync e atualizar arquivos em aproximadamente 20 servidores diferentes.

Eu tenho a parte do rsync descoberta. O que estou tendo problemas é passar por uma lista de variáveis.

Meu script até agora é assim:

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    echo [Server IP Address]
done

Em que [Server IP Address] deve ser o valor da variável associada. Então quando eu = 1 eu deveria ecoar o valor de $ SERVER1.

Eu tentei várias iterações disso, incluindo

echo "$SERVER$i"    # printed the value of i
echo "SERVER$i"     # printer "SERVER" plus the value of i ex: SERVER 1 where i = 1
echo $("SERVER$i")  # produced an error SERVER1: command not found where i = 1
echo $$SERVER$i     # printed a four digit number followed by "SERVER" plus the value of i
echo \$$SERVER$i    # printed "$" plus the value of i

Já faz muito tempo desde que eu escrevi, então sei que estou perdendo alguma coisa. Além disso, tenho certeza de que estou misturando o que eu poderia fazer usando C #, que usei nos últimos 11 anos.

O que estou tentando fazer é possível? Ou devo colocar esses valores em uma matriz e fazer um loop pela matriz? Eu preciso da mesma coisa para endereços IP de produção, bem como nomes de locais.

Isso tudo é um esforço para não ter que repetir um bloco de código que eu usarei para sincronizar os arquivos no servidor remoto.

    
por Paul Stoner 31.07.2018 / 22:45

4 respostas

29

Use uma matriz.

#! /bin/bash
servers=( 192.xxx.xxx.2 192.xxx.xxx.3
          192.xxx.xxx.4 192.xxx.xxx.5
          192.xxx.xxx.6 192.xxx.xxx.7
)

for server in "${servers[@]}" ; do
    echo "$server"
done
    
por 31.07.2018 / 22:55
26

Como as outras respostas apontam, um array é a maneira mais conveniente de fazer isso. No entanto, para fins de conclusão, a exata coisa que você está pedindo é a expansão indireta . Reescrito da seguinte maneira, sua amostra também funcionará usando este método:

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    servervar="SERVER$i"
    echo "${!servervar}"
done

Se você está certo em apenas colocar a lista de endereços IP no loop for , você também pode considerar simplesmente usar algumas expansões de chaves para iterar sobre o que precisar:

#!/bin/bash

for server in \
192.xxx.xxx.{2..7} \
192.yyy.yyy.{42..50} \
192.zzz.zzz.254
do
    echo "$server"
done

Mas se você precisar reutilizar a lista (possivelmente de brace-expandida), usar a lista para inicializar uma matriz seria o caminho a seguir:

#!/bin/bash

servers=(
192.xxx.xxx.{2..7} 
192.yyy.yyy.{42..50}
192.zzz.zzz.254 )

for server in "${servers[@]}"
do
    echo "$server"
done
    
por 01.08.2018 / 00:47
13

Enquanto eu provavelmente iria com uma das respostas da matriz, gostaria de salientar que é possível fazer um loop diretamente sobre os nomes. Você pode fazer

for name in "${!SERVER*}"; do
    echo "${!name}"
done

ou, em 4.3 e acima, você pode usar um nameref :

declare -n name
for name in "${!SERVER*}"; do
    echo "$name"
done

Dica de ilkkachu para os < Solução 4.3.

    
por 01.08.2018 / 03:27
6

Todos que disseram que você deveria usar uma matriz estão corretos, mas - como um exercício acadêmico - se você estava determinado a fazê-lo com variáveis separadas terminadas em um número (SERVER1, SERVER2, etc.), é assim que você faria isso:

for ((i=1; i<7; i++))
do
    eval echo \"\$SERVER$i\"
done
    
por 01.08.2018 / 06:20