Как перебирать переменную, пропуская одно из значений?

Использование ядра 2.6.x

Примечание. В предыдущем вопросе я попытался выполнить это с помощью массива bash. В этой ОС оболочки non-sh устанавливаются как пакеты Entware-NG и не могут использоваться, поскольку они загружаются после запуска сценария.

Цель. Сценарий создания правил iptables с использованием sh (not bash, zsh и т. Д.) Со следующим форматом. Для каждого интерфейса в $ NAME …

  • Создайте правило для его IP-адреса исходной сети из соответствующей позиции в $ NETID. Первое значение в $ NAME имеет исходный сетевой адрес, построенный из первого значения в $ NETID. Например, -i eth1 соответствует -src 192.168.10.0/24 и -i eth2 соответствует 192.168.20.0/24.
  • Создайте IP-адрес назначения для значений в $ NETID, не используемых в исходном сетевом адресе. Например, -src 192.168.10.0/24 -dst 192.168.20.0/24.
  • Стройте каждое правило с одним адресом сети назначения. Не указывайте несколько адресов для значения -dst.

Желаемый результат:

iptables -I FORWARD -i eth1 -src 192.168.10.0/24 -dst 192.168.20.0/24 iptables -I FORWARD -i eth1 -src 192.168.10.0/24 -dst 192.168.30.0/24 iptables -I FORWARD -i eth2 -src 192.168.20.0/24 -dst 192.168.10.0/24 iptables -I FORWARD -i eth2 -src 192.168.20.0/24 -dst 192.168.30.0/24 iptables -I FORWARD -i eth3 -src 192.168.30.0/24 -dst 192.168.10.0/24 iptables -I FORWARD -i eth3 -src 192.168.30.0/24 -dst 192.168.20.0/24 

Проблема: сценарий ниже не создает отношения 1: 1 с именем интерфейса и значением -src. Например, eth1 и 192.168. 10 .0 / 24, eth2 и 192.168. 20 .0 / 24 и т. Д.


 #!/bin/sh NETID="10 20 30" NAME="eth1 eth2 eth3" for i in $NETID; do sarg="192.168.$i.0/24" darg="" for j in $NETID; do [ "$i" -eq "$j" ] && continue darg="192.168.$j.0/24" for k in $NAME; do echo "iptables -I FORWARD -i $k -s $sarg -d $darg -j DROP" done done done 

3 Solutions collect form web for “Как перебирать переменную, пропуская одно из значений?”

Основная проблема заключается в том, что у вас есть соотношение 1: 1 между именами интерфейсов (eth1, eth2, …) и ассоциированными сетями (10.x, 20.x, …), но в вашем коде нет ничего, что явно устанавливает соотношение 1: 1.

Вы должны где-то связывать ethN с 192.168.Nx Вы можете сделать это с помощью одной переменной NETS которая будет содержать список interface:N пар. Смотрите мой код ниже:

 #!/bin/sh NETS="eth1:10 eth2:20 eth3:30" for net in $NETS; do k="${net%:*}" # Yields the name of the interface i="${net#*:}" # Yields the number bound to the interface sarg="192.168.$i.0/24" for net in $NETS; do j="${net#*:}" # Yields the number bound to the interface [ "$i" -eq "$j" ] && continue darg="192.168.$j.0/24" echo "iptables -I FORWARD -i $k -s $sarg -d $darg -j DROP" done done 

Заметки:

  • Я удалил for k in $NAME цикле for k in $NAME целиком, так как кажется, что он противоречит тому, чего вы хотите достичь.
  • Вы даже можете поместить сеть в определение NETS и прочитать sarg и darg непосредственно из нее. Что-то вроде:

     NETS="eth1:192.168.10.0/24 eth2:192.168.20.0/24 eth3:192.168.30.0/24" 

[update] В сочетании с моим ответом на ваш другой вопрос , это даст этот скрипт:

 #!/bin/sh NETID="10 20 30" NAME="eth1 eth2 eth3" NETS=$(set -- $NETID; for iface in $NAME; do echo "$iface:192.168.$1.0/24"; shift; done) for net in $NETS; do iface="${net%:*}" sarg="${net#*:}" for net in $NETS; do darg="${net#*:}" [ "$sarg" != "$darg" ] && echo "iptables -I FORWARD -i $k -s $sarg -d $darg -j DROP" done done 

Используя POSIX Awk, и не беспокоясь о последовательности выходных строк:

 echo | awk -v 'netids=10 20 30' -v 'names=eth1 eth2 eth3' ' BEGIN { netidcount = split(netids, netid) namecount = split(names, name) if (netidcount != namecount) { print "Error: You must pass the same number of names and netids." exit 1 } for (i in name) { for (j in name) { if (i == j) { continue } printf "iptables -I FORWARD -i %s -src 192.168.%s.0/24 -dst 192.168.%s.0/24 -j DROP\n", name[i], netid[i], netid[j] } } }' 

Конечно, вы можете это изменить; например, вы можете поместить awk-скрипт в файл и вызвать его с помощью:

 echo | awk -v ... -v ... -f script.awk 

Или, вы можете поместить netids и имена в data.txt , возможно, отформатированные так:

 eth1 10 eth2 20 eth3 30 

И напишите файл сценария script.awk следующим образом:

 #!/bin/awk NF != 2 { error = 1 print "Error: Each line of input must contain one interface name and one number." exit } (($1 in nameseen) || ($2 in netidseen)) { error = 1 print "Error: Each interface name and network id in input must be unique." exit } { name[NR] = $1 netid[NR] = $2 nameseen[$1] netidseen[$2] } END { if (error) { exit error } for (i in name) { for (j in name) { if (i == j) { continue } printf "iptables -I FORWARD -i %s -src 192.168.%s.0/24 -dst 192.168.%s.0/24 -j DROP\n", name[i], netid[i], netid[j] } } } 

И затем назовите его так:

 awk -f script.awk data.txt 

Много вариантов.

Вероятно, у меня будет data.txt :

 eth1 192.168.10.0/24 eth2 192.168.20.0/24 eth3 192.168.30.0/24 

Изменение скрипта для работы с этим форматом данных остается как упражнение для читателя. 😉


(Примечание: если вы используете этот код, не забудьте указать ссылку на этот ответ в качестве атрибуции.)

Версия POSIX sh:

 for n in 1 2 3; do src="$n"0 interface="eth$n" for dest in 10 20 30; do [ "$dest" = "$src" ] && continue printf 'iptables -I FORWARD -i %s -src %s -dst %s -j DROP\n' "$interface" "192.168.$src.0/24" "192.168.$dest.0/24" done done 

Я сделал некоторые предположения о том, как вы привязываете интерфейс к источнику для своих правил. Но это дает желаемый результат, который вы показали.

  • Извлечь файлы с определенным расширением файла и сохранить структуру каталогов?
  • Порядок обработки и печать файлов с помощью find
  • Как присвоить значение переменной, когда значение содержит символ $ в ней
  • Состояние выхода Bash, используемое с PIPE
  • список папок и их содержимое
  • Как получить PID подпроцесса через родительский процесс в сценарии оболочки bash?
  • Как достичь переменной косвенности (обратитесь к переменной, имя которой хранится в другой переменной) в tcsh
  • Почему я получаю «слишком много аргументов»,
  • почему существует случайное поведение для фоновой работы?
  • Содержит ли жесткие ссылки обычные файлы?
  • Инструмент AIX Non GNU для замены текста
  • Linux и Unix - лучшая ОС в мире.