您好我对TCL编码很新,并在此网站的帮助下编写了此脚本。我想知道是否有更好/更清晰的方式来写这个?
set y [read -nonewline [set f [open "tmp.txt" r]]];
array set counts [list];
foreach message [split $y "\n"] {
# This gets the status, ie: DOWN/UP/OFFLINE.
set status [lindex [split $message] end]; # will assign last field
set mon [lindex [split $message] 1]; # number represents the filed number
set day [lindex lindex[split $message] 2];
if {$day ==""} {
set day [lindex [split $message] 3];
} else {
set day [lindex [split $message] 2]
}
# +number represents the counter
if {[info exists counts($mon,$day,$status)]} {
set counts($mon,$day,$status) [expr {$counts($mon,$day,$status)+1}]
} else {
set counts($mon,$day,$status) 1
}
}
# sort based for down type evetns
puts "\n\nTabl: Down per day"
puts "\n\n MMM DD || Cnt Status"
puts " ====================="
foreach count [lsort -increasing -unique [array names counts]] {
foreach {mon day status} [split $count ","] { break; }
if {$status =="down"} {
puts " $mon $day || [set counts($count)] \t $status"
}
}
# process tunnels that are down and flapped 3 times
array set countsT [list];
foreach message [split $y "\n"] {
# This gets the status, ie: DOWN/UP/OFFLINE.
set status [lindex [split $message] end];
set mon [lindex [split $message] 1];
set day [lindex [split $message] 2];
set Tunnx [lindex [split $message] 9];
if {$day ==""} {
set day [lindex [split $message] 3];
set Tunnx [lindex [split $message] 10]
} else {
set day [lindex [split $message] 2]
}
if {[info exists countsT($mon,$day,$Tunnx,$status)]} {
set countsT($mon,$day,$Tunnx,$status) [expr {$countsT($mon,$day,$Tunnx,$status)+1}]
} else {
set countsT($mon,$day,$Tunnx,$status) 1
}
}
puts "\n\nTabl: Tunnel = Flap >3"
puts "\n\n MMM DD || Tunnelx\tCnt\t Status"
puts " ================================="
foreach count [lsort -increasing -unique [array names countsT]] {
if {[set countsT($count)] < 2} { continue; } {
foreach {mon day tun n status} [split $count ","] { break; }
if {$status =="down"} {
puts " $mon $day || $tun \t [set countsT($count)] \t$status"
}
}
}
if {[info exists f]} { close $f }
示例日志:
670555: Mar 9 23:39:18.214: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670557: Mar 9 23:39:50.877: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670559: Mar 9 23:41:08.662: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel4, changed state to down
670561: Mar 9 23:41:18.309: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel3, changed state to down
670562: Mar 9 23:43:13.237: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670564: Mar 9 23:45:26.549: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670567: Mar 9 23:46:45.708: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel3, changed state to down
670570: Mar 9 23:49:31.222: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670574: Mar 9 23:53:14.295: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670576: Mar 9 23:55:49.217: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670577: Mar 9 23:56:16.180: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670581: Mar 9 23:56:45.480: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel3, changed state to down
670583: Mar 9 23:59:54.080: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670585: Mar 10 00:00:33.224: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670587: Mar 10 00:04:03.292: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670589: Mar 10 00:04:38.921: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel3, changed state to down
670590: Mar 10 00:05:00.505: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670593: Mar 10 00:06:22.473: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670596: Mar 10 00:09:07.262: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670598: Mar 10 00:11:11.294: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
670602: Mar 10 00:14:23.649: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
670604: Mar 10 00:14:59.296: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel2, changed state to down
Results:
Tabl: Down per day
MMM DD || Cnt Status
=====================
Mar 10 || 9 down
Mar 9 || 13 down
Tabl: Tunnel = Flap >3
MMM DD || Tunnelx Cnt Status
=================================
Mar 10 || Tunnel1 4 down
Mar 10 || Tunnel2 4 down
Mar 9 || Tunnel1 2 down
Mar 9 || Tunnel2 7 down
Mar 9 || Tunnel3 3 down
更新:
需要记录当天拍打的隧道数量。
使用下表作为数据参考,新表将是3月10日拍摄的隧道和3月3日3隧道。
我看不出如何计算出另外的tunnelx字段分组来计算数字拍打隧道。
MMM DD || Tunnelx Cnt Status
=================================
Mar 10 || Tunnel1 4 down
Mar 10 || Tunnel2 4 down
Mar 9 || Tunnel1 2 down
Mar 9 || Tunnel2 7 down
Mar 9 || Tunnel3 3 down
答案 0 :(得分:2)
一些注意事项:
while {[gets ...
,如我所示split
仅拆分单个空白字符。我已经演示了使用regexp
来收集字段。我会这样做:
array set counts [list]
array set countsT [list]
set f [open tmp.txt r]
while {[gets $f message] != -1} {
set fields [regexp -all -inline {\S+} $message]
set mon [lindex $fields 1]
# use day "09" instead of "9" so it gets the sorting right.
set day [format %02d [lindex $fields 2]]
# have to be careful to remove the trailing comma from the tunnel
set Tunnx [string trimright [lindex $fields 9] ,]
set status [lindex $fields end] ;# will assign last field
incr counts($mon,$day,$status)
incr countsT($mon,$day,$Tunnx,$status)
}
close $f
# sort based for down type evetns
puts "\n\nTabl: Down per day"
puts "\n\n MMM DD || Cnt Status"
puts " ====================="
# don't need "-unique" flag: array keys will be unique
foreach count [lsort -increasing [array names counts]] {
foreach {mon day status} [split $count ","] { break }
if {$status eq "down"} {
puts [format "%s %s || %3d\t%s" $mon $day $counts($count) $status]
}
}
puts "\n\nTabl: Tunnel = Flap >3"
puts "\n\n MMM DD || Tunnelx\tCnt\t Status"
puts " ================================="
foreach count [lsort -increasing [array names countsT]] {
if {$countsT($count) < 2} { continue }
foreach {mon day tun status} [split $count ","] { break }
if {$status eq "down"} {
puts [format " %s %s || %s\t%3d\t%s" $mon $day $tun $countsT($count) $status]
}
}
答案 1 :(得分:1)
我不确定“更好”,但我想提出一些改变:
set f [open "tmp.txt" r]
set contents [read -nonewline $f]
close $f
array set status_counts {}
array set tunnel_counts {}
foreach message [split $contents "\n"] {
set mon [lindex $message 1]
set day [lindex $message 2]
set tunnel [lindex $message 9]
set status [lindex $message end]
# Do we really need this block?
if {$day ==""} {
set day [lindex $message 3]
set tunnel [lindex $message 10]
} else {
set day [lindex $message 2]
}
set index "$mon,$day,$status"
if {[info exists status_counts($index)]} {
set status_counts($index) [expr {$status_counts($index)+1}]
} else {
set status_counts($index) 1
}
set index "$mon,$day,$tunnel,$status"
if {[info exists tunnel_counts($index)]} {
set tunnel_counts($index) [expr {$tunnel_counts($index)+1}]
} else {
set tunnel_counts($index) 1
}
}
# sort based for down type evetns
puts "\n\nTabl: Down per day"
puts "\n\n"
puts [format "%-3s %2s || %3s %s" MMM DD Cnt Status]
puts [format "%-3s %2s || %3s %s" === == === ======]
foreach count [lsort -increasing -unique [array names status_counts *,down]] {
foreach {mon day status} [split $count ","] { break }
puts [format "%-3s %2s || %3s %s" $mon $day $status_counts($count) $status]
}
puts "\n\nTabl: Tunnel = Flap >3"
puts "\n\n"
puts [format "%-3s %2s || %-8s %-4s %s" MMM DD TunnelX Cnt Status]
puts [format "%-3s %2s || %-8s %-4s %s" === == ======= === ======]
foreach count [lsort -increasing -unique [array names tunnel_counts *,down]] {
if {[set tunnel_counts($count)] < 2} { continue; }
foreach {mon day tun n status} [split $count ","] { break }
puts [format "%-3s %2s || %-8s %-4s %s" $mon $day $tun $tunnel_counts($count) $status]
}
以下是我所做的改变以及我背后的想法。这些是我的意见,因此你可能会或可能不同意我的意见。
Tcl不需要用分号结束一行,所以我宁愿看不到它们,这有助于代码的清晰度。
打开并读取文件作为两个单独的步骤。如果出现错误,我知道哪个步骤会导致问题,从而使调试更容易。
我喜欢在完成后立即关闭文件,而不是在脚本结束时。
将两个循环合并为一个。你有两个循环,每个循环都有相似但略有不同的步骤。我将它们组合成一个循环,这减少了代码量,复杂性和错误机会。
我更喜欢拼写出来的标识符名称,而不是缩写。例如,我更喜欢 tunnel_counts 而非 countsT
在调用lindex
之前无需拆分消息。在大多数情况下,Tcl处理字符串并以相同的方式列出。这意味着字符串可以作为列表,项目用空格分隔。
在第一个循环中,我不理解为$day == ""
测试的代码块,所以我只留下该块。我怀疑你不需要它。
我介绍了变量index
,它减少了输入,使代码更清晰,并减少了出错的可能性。
我没有在两个报告循环中测试$status == "down"
,而是将过滤器应用于array names
命令:[array names tunnel_counts *,down]
。这消除了这些循环中的if
语句。
格式化更改以更好地对齐
最后,原始代码的缩进不一致:有时你用4个空格缩进,有时用8缩进。这可能与你在编辑器中设置标签的方式有关。
重要的是要注意,您的原始脚本工作得很好。我建议的改变是为了便于阅读,理解和维护。