Continuous display of top CPU processes

When you have to monitor which processes consume router’s CPU over a period of time, a Tcl script that emulates the Unix top command might come handy. The following Tcl script continuously displays top 20 Cisco IOS processes and refreshes the update every 5 seconds.

The following text written by Ivan Pepelnjak in 2008 was originally published on CT3 wiki. That web site became unreachable in early 2019. We retrieved the original text from the Internet Archive, cleaned it up, updated it with recent information if necessary, and republished it on blog on November 17, 2020


  • Download the source file into flash:top.tcl.
  • Configure alias exec top tclsh flash:top.tcl.
  • Invoke with top.

Usage guidelines

Usage: top [ 5sec | 1min | 5min ]

The script changes the escape character to Ctrl/C. Use terminal escape default to restore default settings

If anyone discovered a reliable technique that detects a keypress event (= character available on stdin) in the Tcl loop, please let me know. The Ctrl/C solution is a kludge.

Source code

# title:    Emulate the Unix top command
# name:     top.tcl
# desc:     The script displays top CPU processes every 5 seconds
# ios config:
#           * download the file into flash:top.tcl
#           * configure alias exec top tclsh flash:top.tcl
#           invoke with top [5sec|1min|5min]

set IOS [string equal $tcl_platform(os) "Cisco IOS"];

if { $IOS } { 
  exec "terminal international"; 
  exec "terminal escape 3";

set arg [lindex $argv 0];
if { [string length $arg] == 0 } { set arg "5sec" } ;
if { [lsearch -exact { 5sec 1min 5min } $arg] < 0 } {
  puts {Usage: top [5sec|1min|5min]};
  return 0;

fconfigure stdout -buffering none;

while {1} {
  set lines [split [exec "show process cpu sorted $arg | exclude 0.00% +0.00% +0.00%"] "\n"];

  puts -nonewline "\033\[2J\033\[H";
  for { set lc 1 } { $lc < 23 } { incr lc } {
    set curline [lindex $lines $lc];
    if { [string length $curline] > 0 } { puts "$curline"; }
  puts -nonewline "\nBreak with Ctrl/C --> ";
  after 5000;


  1. Ivan, in latest IOS (12.2(33)SRC) you can use the "monitor" keyword in various show commands to accomplish the same thing: monitor something continuously.

    router#sh proc cpu monitor interval 5

    But i always enjoy your tcl (& eem) approaches ;)
  2. Thanks mate, Cool :)
  3. @Tassos: I've only found the "monitor" keyword in the "show proc cpu" and "show int" command. Check with show parser dump exec | inc show.*[a-z]+.*monitor interval.
  4. Tassos,
    I can't find anything like monitor interval in my routers.. :)

    Mr Ivan,
    Well, I would love to replace your show process command with this

    set lines [split [exec "show process cpu sorted $arg | exc 0.00%__0.00%__0.00% "] "\n"];

    This way you can list only the process being used for Router instead of all (long list)
  5. @Ivan : I guess "various" got interpreted as more than 2 ;)
    At least these 2 commands are the most used when referring to a continuous "show" operation.

    @massood, you need the latest 12.2(31)SB or 12.2(33)SRC to see it. Not all platforms support these releases.
  6. You're absolutely right ... various could also mean two :))

    I learn something new every day ;)
  7. "terminal exec prompt timestamp" is also interesting to know the CPU utilization each time a command is typed.
  8. Tassos, does the <show> have any impact on the routers performance?</show>
  9. Ivan, your script is very useful - I've been using it on 12.4(12c). But on 15.0(1r)M9 it does not clear the screen. If I execute "terminal international" and "terminal escape 3" BEFORE I start the script than it's ok. Any idea why?

    Also, if numbers under "Invoked" get too big the lines wrap so I modified output to:

    set curline [lindex $lines $lc];
    # if { [string length $curline] > 0 } { puts "$curline"; }
    set cutline "[string range $curline 0 78]"
    if { [string length $curline] > 0 } { puts "$cutline"; }

    Hope you don't mind :)
  10. The "terminal international" command is needed to enable router to send the escape character (chr(27)) as one character, not as ^[ sequence.
Add comment