Como iterar através de uma matriz bash ao remover um elemento?

1

GNU bash , versão 4.3.42 (1) -release (arm-openwrt-linux-gnu)

Estou tentando fazer o script de uma regra iptables usando uma matriz bash.

$ NETID é usado para criar endereços de rede. Por exemplo, 192.168. 10 .0 / 24, 192.168. 20 .0 / 24, etc.

Estou tentando criar uma variável temporária ($ NETID_TMP) onde o "i" em $ {NETID [@]} é removido de $ NETID_TMP. Por exemplo, se "i" = 10, NETID_TMP = (20 30 40).

Script:

    #!/opt/bin/bash
    NETID=(10 20 30 40)
    for (( i=0; i<${#NETID[@]}; i++ )); do
       NETID_TMP=(${NETID[*]})
       unset NETID_TMP[${NETID[i]}]
       iptables -I FORWARD -s 192.168.${NETID[i]}.0/24 -d 192.168.${NETID_TMP[0]}.0/24,192.168.${NETID_TMP[1]}.0/24,192.168.${NETID_TMP[2]}.0/24 -j DROP
    done

O resultado deve ser ...

iptables -I FORWARD -s 192.168.10.0/24 -d 192.168.20.0/24,192.168.30.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.20.0/24 -d 192.168.10.0/24,192.168.30.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.30.0/24 -d 192.168.10.0/24,192.168.20.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.40.0/24 -d 192.168.10.0/24,192.168.20.0/24,192.168.30.0/24 -j DROP
    
por uihdff 02.09.2017 / 06:23

2 respostas

3
netid=(10 20 30 40)

for i in "${netid[@]}"; do
    out="iptables -I FORWARD -s 192.168.$i.0/24 -d "

    for j in "${netid[@]}"; do
        (( i == j )) && continue
        out+="192.168.$j.0/24,"
    done
    out="${out%,} -j DROP"

    printf '%s\n' "$out"
done

Este script Bash produz

iptables -I FORWARD -s 192.168.10.0/24 -d 192.168.20.0/24,192.168.30.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.20.0/24 -d 192.168.10.0/24,192.168.30.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.30.0/24 -d 192.168.10.0/24,192.168.20.0/24,192.168.40.0/24 -j DROP
iptables -I FORWARD -s 192.168.40.0/24 -d 192.168.10.0/24,192.168.20.0/24,192.168.30.0/24 -j DROP

através de um loop duplo. O loop interno ignora as iterações em que a variável de loop é numericamente igual à variável de loop do loop externo para criar o efeito desejado.

Depois de ter a string em $out , você pode usar eval .

Como alternativa, evite eval :

netid=(10 20 30 40)

for i in "${netid[@]}"; do
    sarg="192.168.$i.0/24"
    darg=""

    for j in "${netid[@]}"; do
        (( i == j )) && continue
        darg+="192.168.$j.0/24,"
    done
    darg="${darg%,}"

    iptables -I FORWARD -s "$sarg" -d "$darg" -j DROP
done

A substituição de variável ${parameter%word} removerá word do final de $parameter , então darg="${darg%,}" removerá a vírgula no final af $darg .

Atualização após pergunta no comentário:

A única coisa bash -específica sobre o que foi dito acima é o uso da matriz $netid , o operador += para anexar à string $darg e ((...)) . Podemos transformar isso em um script sh como este (aqui assumindo que $IFS ainda tenha seu valor padrão):

netid="10 20 30 40"

for i in $netid; do
    sarg="192.168.$i.0/24"
    darg=""

    for j in $netid; do
        [ "$i" -eq "$j" ] && continue
        darg="${darg}192.168.$j.0/24,"
    done
    darg="${darg%,}"

    iptables -I FORWARD -s "$sarg" -d "$darg" -j DROP
done

Se você tiver uma lista separada de números que deseja inserir em $darg , use-a no loop interno no lugar de $netid . Deve ser uma sequência de números separados por espaços.

    
por 02.09.2017 / 08:59
1

É mais fácil com zsh :

#! /bin/zsh -
nets=(192.168.{10,20,30,40}.0/24)
for net ($nets) iptables -I FORWARD -s $net -d ${(j:,:)nets:#$net} -j DROP
    
por 04.09.2017 / 16:34