1

我有一个类似的清单

set val [ list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 ]

现在我想把它放在一个循环中并在每个范围内执行一些命令

set number 0
set pattern 0
foreach n $val {
    if {$pattern == 0} {
        set current $n
        regexp {(.*/)(\d+)} $n - pattern number
        continue
    }

    regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
        #puts "someproc $current - match2"
    }
}

我无法完成这项工作,输出应该类似于 ech 对或找到的奇异值

someproc Fa2/0/1 - 24
someproc Gi1/0/13 - 23
someproc Gi1/1/1 - 1       #for singular values
someproc Gi2/0/1 - 1

编辑:我有一个这样的数据列表:

  Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1

您可以在其中说每个数据可以是类型,或者Gi3/0/这些数据可以代表cisco swicth 上的某些端口范围。现在,对于每种类型,我都需要为一个范围执行一些命令。再次获取上面的列表,我可以获得。Gi2/0/Fa2/0/

somecommand Gi3/0/1 - 1 # there is only one `Gi3/0/` with number 1.
somecommand Fa2/0/1 - 24 # range of `Fa2/0/` is 1 to 24

相似地,

somecommand Gi1/0/13 - 23
somecommand Gi1/1/1 - 1
and so on
4

7 回答 7

1
#!/usr/bin/tcl

## Assumptions:
## The pattern will always be X/X/X
##  The values are given in list
set val_list [list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1]

array set pattern {}

foreach item $val_list {
set parent [file dir $item]
set val [file tail $item]
if {[info exists pattern($parent,L)] && [info exists pattern($parent,H)]  } {
    if {$pattern($parent,L) > $val } {
    set pattern($parent,L) $val
    } elseif { $pattern($parent,H) < $val} {
    set pattern($parent,H) $val
    }
} else {  
    set pattern($parent,L) $val
    set pattern($parent,H) $val 
}
}
array set count {}
foreach pat  [array names pattern] {
set pat [lindex [split $pat ,] 0]
if {![info exists count($pat)] } {
    puts "$pat $pattern($pat,L) - $pattern($pat,H)"
    set count($pat) 1
}
}


/*The output will be 
Gi1/0 13 - 23
Fa2/0 1 - 24
Gi2/0 1 - 1
Gi1/1 1 - 1
*/

希望这是您所要求的。我使用数组“count”来删除输出中的重复条目,这是需要避免的。希望有人能提出更好的方法。仅供参考,我使用的是 8.4 版本的 TCL。

于 2013-04-25T12:36:31.200 回答
1

如果您不确定数组是如何工作的,您可以编辑您发布的作为此代码答案的代码:

set number 0
set pattern 0
set current 0
set result [list Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1]

foreach n [lsort $result] {
  if {$pattern == 0} {
        set current $n
    regexp {(.*/)(\d+)} $n - pattern number
    continue
  }
  regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
        set number $match2
    } else {
        puts "$current - $number"
        set pattern $match1
        set number $match2
        set current $n
    }
}

这对我行得通 :)

输出(请注意,我首先对列表进行了排序,因此您只需要担心增加$number$match2不必过多担心$pattern):

Fa2/0/1 - 24
Gi1/0/13 - 23
Gi1/1/1 - 1
Gi2/0/1 - 1
Gi3/0/1 - 1
于 2013-04-25T17:41:47.203 回答
1

这是我的解决方案,它不使用数组(数组没有任何问题,我的解决方案只是不需要它),并且它一次性完成(即只有一个循环)。

set val [ list Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 ]
set lastPattern ""
set lastNumber 0
lappend val x/1/1; # Add a trailer to ease processing

foreach item $val {
    # If item=Fa2/0/1, then pattern=Fa2/0 and number=1
    set pattern [file dirname $item]
    set number  [file tail $item]

    if {$pattern == $lastPattern} {
        # We have seen this pattern before
        puts "$pattern/$lastNumber - $number"
        set lastPattern ""
    } else {
        # This is a new pattern, print the old one if applicable then
        # save the pattern and number for later processing
        if {$lastPattern != ""} {
            puts "$lastPattern/$lastNumber - $lastNumber"
        }
        set lastPattern $pattern
        set lastNumber $number
    }
}
set val [lrange $val end-1]; # Remove the trailer
于 2013-04-25T20:14:30.757 回答
1

for如果要比较相邻的列表元素,使用 C 风格的循环可能更简洁:

for {set i 0} {$i < [llength $val] - 1} {incr i} {
    set current [lindex $val $i]
    set next    [lindex $val [expr {$i+1}]]

    # ...
}

或者,更深奥一点

set l {a b c d e f g}
foreach current [lrange $l 0 end-1] \
        next    [lrange $l 1 end] {
    puts "$current $next"
}

输出

a b
b c
c d
d e
e f
f g

你甚至可以编写一个新的控制结构,类似于 Ruby 的each_cons

proc foreach_cons {vars list body} {
    foreach varname $vars {upvar 1 $varname $varname}
    set numvars [llength $vars]
    for {set i 0} {$i <= [llength $list]-$numvars} {incr i} {
        lassign [lrange $list $i [expr {$i + $numvars}]] {*}$vars
        uplevel 1 $body
    }
}
foreach_cons {a b c} $l {puts "$a $b $c"}
a b c
b c d
c d e
d e f
e f g
于 2013-04-25T21:09:56.283 回答
0

你为什么不循环列表

foreach {v1 v2} $val {
     someproc $v1 $v2
}

您可以检查两个值是否相似,提取您需要的部分等。

于 2013-04-25T08:02:22.027 回答
0

我想出了我自己的一个尴尬的解决方案:其中 reslut 是列表:

  Gi3/0/1 Fa2/0/1 Fa2/0/24 Gi1/0/13 Gi1/0/23 Gi1/1/1 Gi2/0/1 Te1/0/1

#

set number 0
set pattern 0
set last_element [lindex $result end]
set first_element [lindex $result 0]
foreach n $result {
    if {$pattern == 0} {
        set current $n
        set count 0
        regexp {(.*/)(\d+)} $n - pattern number
        continue
    }
    regexp {(.*/)(\d+)} $n - match1 match2
    if {$match1 == $pattern} {
    set count 0
    puts " $current - $match2"
        continue
     } else {
             if {"$last_element" == "$n"} {
             puts "$last_element"
             }
             if {"$first_element" == "$current"} {
             puts "$first_element"
             }
             incr count
             if {"$count" == 1} {
             set pattern $match1
             set current $n
             continue
             } else {
                     if {$match1 != $pattern} {
                     puts "$current"
                     }

             }
     set pattern $match1
     }
        set current $n

}
于 2013-04-25T13:19:09.090 回答
0

此解决方案稍短一些,但需要 Tcl 8.5。

首先,创建一个字典结构,其中前两个字段作为键和子键,并从第三个字段收集值列表作为字典值:

set data {}
foreach v $val {
    lassign [split $v /] a b c
    if {![dict exists $data $a $b]} {
        dict set data $a $b {}
    }
    dict with data $a {
        lappend $b $c
        set b [lsort –integer $b]
    }
}

然后遍历这个字典结构,someproc为键、子键、第一个和最后一个值的每个组合调用命令。

dict for {a v} $data {
    dict for {b v} $v {
        someproc $a/$b/[lindex $v 0] - [lindex $v end]
    }
}

文档:dictforeachiflappendlassignlindexsetsplit

于 2016-04-25T11:03:08.570 回答