The RC File

Each tclsh or wish can have its own RC file:

  • The RC file is normally named .tclshrc, .wishrc or a variation on that, tied to the specific tclsh. On Windows, it becomes tclshrc.tcl or wishrc.tcl

[What happens on MacOS - does it expect startup script in a mac file resource? Well, in tcl8.4.6/mac/tclMacAppInit.c, it appears that the default is to look for a TEXT resource called tclshrc.]

  • The default RC files are $(HOME)/.tclshrc and $(HOME)/.wishrc under UNIX, and %HOME%\tclshrc.tcl and %HOME%\wishrc.tcl under MS Windows. %HOME% is not set by default in MS Windows, and in this case %HOME% (and $env(HOME) within the shell) default to C:\
  • The RC file is automatically sourced when the shell is started interactively (without a script on its commandline)
  • The RC file is not automatically sourced when the shell is started with a script on the commandline, or from a shellscript using the #!/usr/bin/tclsh type notation
  • RC files have the full language as implemented by the specific shell. itkwishrc thus can use [incr Tcl] and Tk.
  • When the shell is deemed interactive, the global variable $tcl_interactive is true.

Also see Application-specific RC files.


Use the rc file for items you want to always have available when working interactively. This may be special error analysis procedures, defining a prompt that is more descriptive than a plain %, and more. Because you will be using the tclsh in interactive mode even in debugging scripts intended to run without that level of interactivity, avoid cluttering the global namespace unduely.

Remember, though, that the ~/.tclshrc will be sourced by older tclsh versions if you have them installed, and similarly with wishrc files. You may have to condition some code or usages on version of Tcl provided by the current interpreter, which is the result of [package provide Tcl]. At the same time, if you are using a platform which uses symbolic links, you may wish to combine a tclshrc and itclshrc, expectrc, and the like.

Similarly, one rc file can source another, again saving multiple editing of varied rc files.

LV One of the more common reports from new Tcl writers has to do with why does things work one way when I am typing commands into Tcl interactively but a different way when I am running a script.' One answer has to do with the RC file. There are other factors however, like some behaviors only occuring when in interactive mode.

Ideas for a useful tclshrc

A really nice feature would be keeping the command history and using the cursor keys to scroll through it. This would probably be easy if I just understood slightly more about the scoping rules.

global tcl_interactive tcl_prompt1 tcl_prompt2
# Configure the prompt according to the actual (non-wish) running
# First, only bother with a prompt IF it is an interactive shell
# We may wish to source from other scripts just for convenience
if {[info exists tcl_interactive] && $tcl_interactive > 0} {
   set tcl_prompt1 {global tcl_version
      puts -nonewline "=========\ntclsh$tcl_version > "}
   set tcl_prompt2 {puts -nonewline "continue > "}
   if {[info exists itcl::patchLevel]} {
      set tcl_prompt1 {puts -nonewline "=========\nitclsh$::itcl::patchLevel > "}
      set tcl_prompt2 {puts -nonewline "continue > "}
   } elseif [string match exp_version [info command exp_version]] {
      set tcl_prompt1 {puts -nonewline "========\nexpect[exp_version] > "}
      set tcl_prompt2 {puts -nonewline "continue > "}
   } elseif {[info exists tnm(version)]} {
      set tcl_prompt1 {global tnm
         puts -nonewline "=========\nscotty$tnm(version) > "}
      set tcl_prompt2 {puts -nonewline "  continue >  "}
   } elseif {[llength [info commands pg_connect]] > 0} {
      regsub {tclsh} $tcl_prompt1 {pgtclsh}

# Convenience procs
proc showenv {} {
   global env
   foreach k [lsort [array names env]] {
      puts "$k=\"$env($k)\""

Ideas for a useful wishrc

global tcl_interactive tcl_prompt1 tcl_prompt2 tk_patchLevel 
# Again, test for tcl_interactive true before setting prompts
if {[info exists tcl_interactive] && $tcl_interactive > 0} {
   source ~/.tclshrc
   if [string match exp_version [info command exp_version]] {
      set tcl_prompt1 { puts -nonewline "========\nexpectk[exp_version] > "  }
   } elseif [info exists ::itk::patchLevel] {
      set tcl_prompt1 { puts -nonewline "========\nitkwish$::itk::patchLevel > "}
   } elseif [info exists ::itcl::patchLevel] {
      set tcl_prompt1 {
      puts -nonewline "========\n\[i$::itcl::patchLevel\]wish $tk_patchLevel > "}
   } else {
      set tcl_prompt1 {global tk_version
      puts -nonewline "=========\nwish $tk_patchLevel > "}
   set tcl_prompt2 { puts -nonewline "continue > "}

A little tool to list the available packages

Here's a little utility that I'm beginning to find invaluable... Usage: lspackages ? pattern ? lists all the package names and versions installed on the system, along with the 'package require' script that will be executed to loade them. Packages that have already been loaded are prefixed with a '+' sign. --JE

 proc lspackages {{pattern *}} {
     # Force the package loader to do its thing:
     # NOTE: this depends on a side effect of the
     # built-in [package unknown].  Other [package unknown]
     # handlers might not meet our expectations.
     eval [package unknown] Tcl [package provide Tcl]
     foreach package [lsort [package names]] {
        if {![string match $pattern $package]} { continue }
        foreach version [package versions $package] {
            set present [expr {
                [string compare $version [package provide $package]]
              ? " " : "+" }]
            set ifneeded \
                [string replace \
                    [string trim \
                        [string map {"\n" " " "\t" " "} \
                            [package ifneeded $package $version]]] \
                    50 end "..."]
            puts [format "%1s%-15s %6s %-55s" \
                $present $package $version $ifneeded]

DKF: My .tclshrc is extremely simple:

 proc % {args} {uplevel 1 $args}

This makes it much easier to mark-n-paste previously entered lines for inputting again as I don't need to be careful with excluding the prompt. :^)

aspect: I have a bunch of useful snippets from the wiki and interactive helpers in ~/tcl.d/, which I auto-load with the following .tclshrc code:

if {$tcl_interactive} {
    foreach tcl [lsort [glob -directory ~/tcl.d -type f *.tcl]] {
        if {$tcl in [list ~/tcl.d/pkgIndex.tcl ~/tcl.d/tclshrc.tcl]} {
            puts "no $tcl"
        if [file readable $tcl] {
            puts ">> $tcl"
            source $tcl

DGP: I made a few revisions above to advise better use of [package].

Examples of clever use of .*rc appear several places. Note that "Magic names" has more information on the .*rc mechanism.

TP Some folks may want to ask Why is is called an RC file? See: [L1 ] and [L2 ]