views:

406

answers:

2

Hi Folks, I am beginner to scripting and vigorously learning TCL for the development of embedded system.

I have to Search for the files with only .txt format in the current directory, count the number of cases of each different "Interface # nnnn" string in .txt file, where nnnn is a 4 to 32 digits max hexadecimal number and o/p of a table of Interface number against occurrence. I am facing implementation issues while writing a script i.e, Unable to implement the data structure like Linked List, Two Dimensional array. I am rewriting a script using multi dimension array (Pass values into the arrays in and out of procedure) in TCL to scan through the every .txt file and search for the the string/regular expression ‘Interface # ’ to count and display the number of occurrences. If someone could help me to complete this part will be much appreciated.

Search for only .txt extension files and obtain the size of the file

Here is my piece of code for searching a .txt file in present directory

set files [glob *.txt]
if { [llength $files] > 0 } {
    puts "Files:"
    foreach f [lsort $files] {
        puts "    [file size $f] - $f"
    }
} else {
    puts "(no files)"
}

I reckon these are all the possible logical steps behind to complete it i) Once searched and find the .txt file then open all .txt files in read only mode ii) Create a array or list using the procedure (proc) Interface number to NULL and Interface count to zero 0 iii) Scan thro the .txt file and search for the string or regular expression "interface # iv) When a match found in .txt file, check the Interface Number and increment the count for the corresponding entry. Else add new element to the Interface Number list v) If there are no files return to the first directory

My o/p is like follows

Interface    Frequency
123f            3
1232            4
+1  A: 

Edited to use an array by name instead of global variable.

I think you'd want something along the lines of this. You'd call scan_for_interface on each file, and at the end call print_report. You can get fancier and wrap this in an Itcl class, or a namespace. The second argument to scan_for_interface is the name of the array in which to store the results, and that name is passed to print_report. The regexp link will describe how regexp works:

proc scan_for_interface {file arrayname} {
  upvar $arrayname array
  set fh [open $file r]
  while {[gets $fh line] >= 0} {
    if {[regexp -- {Interface # ([[:xdigit:]]{4}|[[:xdigit:]]{32})$} $line ignore num]} {
      if {[info exists array($num)]} {
        incr array($num)
      } else {
        set array($num) 1
      }
    }
  }
  close $fh
}

proc print_report {arrayname} {
  upvar $arrayname array
  puts "Interface    Frequency"
  set fmt "%s             %d"
  foreach {interface number} [array get array] {
    puts [format $fmt $interface $number]
  }
}

# the following is a proc that takes the question's code
# and incorporates the calls to the accounting functions
proc dosearch {} {
  set files [glob *.txt]
  if { [llength $files] > 0 } {
    puts "Files:"
    foreach f [lsort $files] {
      puts "    [file size $f] - $f"
      scan_for_interface $f tally
    }
    print_report tally
  } else {
    puts "(no files)"
  }
}
Trey Jackson
I'd leave out the summing in `print_report`; that appears to have been a typo in the original question. Otherwise, a pretty good answer. (Personally, I'd use `global global_array` inside `scan_for_interface` but that's a minor thing.)
Donal Fellows
The regex can be `{Interface # ([[:xdigit:]]{4}|[[:xdigit:]]{32})$}`
glenn jackman
@glennjackman thanks.
Trey Jackson
@ Trey Jackson Thank you very much
Passion
@Passion I wrote a `dosearch` proc that contains your initial code with the calls. I don't see any syntax errors, and in fact ran the above code with success. If you're still having problems, you'll need to give more details.
Trey Jackson
Passion
Passion
A: 

Not being a big fan of globals, I'd go with something like what Trey used, but have it return a dict (or array get) of the results for the current file, and merge them into a dict (or array) maintained at the caller level.

RHSeeger