値の1つをスキップしながら変数を繰り返すには?

値の1つをスキップしながら変数を繰り返すには?

カーネル2.6.xの使用

メモ:以前の質問では、これを行うためにbash配列を使用しようとしました。このオペレーティングシステムでは、sh以外のシェルがEntware-NGパッケージとしてインストールされ、スクリプトの実行後にロードされるため、使用できません。

ターゲット:スクリプトを使用したiptablesルールの作成シェン(bash、zshなどではありません)形式は次のとおりです。 $ NAMEの各インターフェースについて...

  • $ NETIDのその場所にソースネットワークIPアドレスのルールを作成します。 $ NAMEの最初の値は、$ NETIDの最初の値で構成されたソースネットワークアドレスを持ちます。たとえば、-i eth1 は -src 192.168.10.0/24 に対応し、-i eth2 は 192.168.20.0/24 に対応します。
  • 送信元ネットワークアドレスに使用されていない$NETIDの値の宛先IPアドレスを作成します。たとえば、-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

質問:次のスクリプトは、インターフェース名と-src値の間に1:1の関係を生成しません。たとえば、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

答え1

出力ラインの順序を気にせずに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

data.txtまたは、ネットワークIDと名前を次の形式で入力できます。

eth1 10
eth2 20
eth3 30

script.awkそして、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

このデータ型を使用するようにスクリプトを変更することは、読者の練習課題として残されます。 ;)


(注:このコードを使用している場合は、この回答へのリンクを帰属として含めることを忘れないでください。)

答え2

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

インターフェイスをルールソースに接続する方法についていくつかの仮定をしました。しかし、それはあなたが示している望ましい結果を生み出します。

答え3

主な問題は、インターフェイス名(eth1、eth2、...)と関連ネットワーク(10.x、20.x、...)の間に1:1の関係がありますが、コードではそれを作成しないことです。 1:1関係が確立されました。

どこかにethNバインドする必要があります。192.168.N.xペアリストを含む単一の変数を使用して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達成したい目標と矛盾しているようで、ループを完全に削除しました。
  • ネットワークを定義に入れてNETS直接読むこともできます。それは次のとおりです。sargdarg

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

[更新]結合他の質問に対する私の答え、次のスクリプトを提供します。

#!/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

関連情報