Bourne shell: 根据多个条件拆分字符串(iptables 多端口限制)

Bourne shell: split string according to multiple criteria (iptables multiport limitation)

我正在 Bourne shell 中编写一个例程来命令 iptables,它大量使用 "multiport" 参数。

iptables 允许最多 15 次引用 multiport 参数。这些引用可以是单独的(计数 1)或范围(计数 2)。

我需要以 iptables 多端口可用的方式打破一长串混合在单个和范围之间的端口。

例如给定一个包含 18 个引用、18 个单独端口和 2 个范围的列表:

21,22,23,24,25,26,27,28,29,30:40,60,61,62,63,64,65:70

我正在尝试找到一种方法将字符串和任何类似的字符串拆分为最多 15 个引用的集合,例如在本例中 15+3:

21,22,23,24,25,26,27,28,29,30:40,60,61,62,63
64,65:70

诀窍在于:范围不能拆分为不同的行。所以如果原来的输入是:

21,22,23,24,25,26,27,28,29,30:40,60,61,62,63:64,65:70

我需要拆分 (14+4):

21,22,23,24,25,26,27,28,29,30:40,60,61,62
63:64,65:70

有什么聪明的方法可以实现这一点,也许是使用 awk?

这是一个简单的 Awk 脚本,可以在同一行收集尽可能多的同类项目。

awk -v RS=',' -F : '{ gsub(/\n$/, "") }
    NF > 1 { r=(r ? r "," : "") [=10=];                                                                              
        if (r ~ /([^,]*,){6}/) { print r; r=""; } next }                        
    { s=(s ? s "," : "") [=10=];                                                    
        if (s ~ /([^,]*,){14}/) { print s; s=""; } }                            
    END { if (r && s) {                                                         
            p = r "," s; if (p !~ /([^,:]*[:,]){15}/) { print p; r=s="" } }     
        if (r) print r ; if (s) print s }'

更改后的 RS(记录分隔符)意味着逗号被分割为换行符,并且在这些记录 ("lines") 中,冒号被视为字段分隔符。然后我们只是检查输入中是否有两个以上的字段,并在打印一批之前收集最多 8 对或 15 个单例。

随着输入

21:22,23,24,25,26,27,28,29,30:40,60,61,62,63,64,65:70

它打印

21:22,30:40,65:70
23,24,25,26,27,28,29,60,61,62,63,64

你可以在这里玩:http://ideone.com/a3PCzs