1

こんにちは私は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

アップデート:

1日にフラップしたトンネルの数を記録するために必要です。

以下の表をデータ参照に使用すると、新しい表は、フラップしたMar102トンネルとMar9th3トンネルになります。

フラップされたトンネルの数をカウントするために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
4

2 に答える 2

2

いくつかのメモ:

  • ファイルを2回ループする必要はなく、最初のループで配列を累積するだけです。
  • ファイルを1行ずつ読み取る慣用的な方法は、while {[gets ...私が示したとおりです。
  • splitご覧のとおり、1つの空白文字でのみ分割されます。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]
    }
}
于 2013-03-12T22:09:52.233 に答える
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]
}

ディスカッション

以下は、私が行った変更とその背後にある私の考えです。これらは私の意見であり、あなたは私に同意するかもしれないし、同意しないかもしれません。

  1. Tclはセミコロンで行を終了する必要がないので、私はむしろそれらを見ません。これはコードの明確さを助けます。

  2. 2つの別々のステップとしてファイルを開いて読み取ります。エラーが発生した場合、どのステップが問題の原因であるかがわかっているので、デバッグが容易になります。

  3. スクリプトの最後ではなく、完了したらすぐにファイルを閉じることを好みます。

  4. 2つのループを1つに結合します。2つのループがあり、それぞれが類似していますが、わずかに異なるステップを実行します。それらを1つのループに結合し、コードの量、複雑さ、およびエラーの可能性を減らします。

  5. 私は、省略形ではなく、綴られた識別子の名前を好みます。たとえば、countsTよりtunnel_countsの方が好きです

  6. を呼び出す前にメッセージを分割する必要はありませんlindex。ほとんどの場合、Tclは文字列とリストを同じように扱います。つまり、文字列は、スペースで区切られた項目を含むリストとして機能できます。

  7. 最初のループでは、をテストするコードのブロックがわからないため、そのブロックを$day == ""そのままにしておきます。私はあなたがそれを必要としないだろうと思う。

  8. 変数を導入しましたindex。これにより、入力が減り、コードがすっきりし、エラーが発生する可能性が減ります。

  9. $status == "down"2つのレポートループ内でテストする代わりに、array namesコマンドにフィルターを適用しました[array names tunnel_counts *,down]ifこれにより、これらのループ内のステートメントが削除されます。

  10. アライメントを改善するためのフォーマット変更

  11. 最後に、元のコードのインデントは一貫していません。4つのスペースでインデントする場合もあれば、8でインデントする場合もあります。これは、エディター内でタブを設定する方法に関係している可能性があります。

  12. 元のスクリプトは問題なく機能することに注意してください。私が提案する変更は、読みやすく、理解しやすく、保守しやすいようにするためのものです。

于 2013-03-12T21:58:13.903 に答える