Writing a Hello World Script
The smallest useful Tcl script is a single line: puts "Hello, world!", where puts writes its string argument to standard output followed by a newline (use puts -nonewline to suppress it). Comments start with # as the first non-whitespace character of a command — importantly, # only introduces a comment where a new command is expected, so a stray # after other content on the same logical line (without a preceding ;) is not treated as a comment, which trips up newcomers coming from languages where # always comments out the rest of a physical line.
Cricket analogy: Just as the very first ball of a match is a simple, low-risk delivery to get things underway, puts "Hello, world!" is the simplest possible Tcl statement to get a script running and producing visible output.
Adding Logic: Procedures and Control Flow
A reusable block of logic is defined with proc name {args} {body}, e.g. proc greet {name} { puts "Hi, $name!" }, and called just like any built-in command: greet Ada. Control flow uses if/elseif/else for branching and foreach/while/for for iteration, all following the same brace-quoted-body convention already covered, so foreach n {1 2 3} { puts $n } prints each of 1, 2, and 3 on its own line, and if {$score >= 80} { puts pass } else { puts fail } branches on a boolean expression.
Cricket analogy: Just as a bowling coach teaches a repeatable bowling action that any bowler can then execute on demand, proc greet {name} { ... } defines a repeatable block of logic that can be called on demand with greet Ada.
Taking Input
Reading a line typed by the user is done with gets stdin line, which reads one line of standard input into the variable line and returns the number of characters read (or -1 at end-of-file), so a common pattern is puts -nonewline "Name: "; flush stdout; gets stdin name. Command-line arguments passed to a script are available as the list $argv (and its count as $argc), while $argv0 holds the script's own invocation name, letting a script branch on how many arguments were supplied with if {$argc != 2} { puts "Usage: $argv0 <a> <b>" ; exit 1 }.
Cricket analogy: Just as an umpire waits for the bowler to complete their delivery before signaling the outcome, gets stdin line waits for the user to type a full line and press Enter before the script continues.
From Console Script to Tk GUI
Turning a console script into a graphical one starts with package require Tk (unnecessary under wish, which loads it automatically), after which widgets like label .l -text "Enter your name:", entry .e -textvariable name, and button .b -text OK -command { puts "Hello, $name!" } are created and then placed on screen with a geometry manager, most simply pack .l .e .b. Event handling beyond button clicks uses bind, e.g. bind .e <Return> { puts "Hello, $name!" } runs the same script when the Enter key is pressed while the entry widget has focus, which is how Tk GUIs respond to keyboard and mouse events generally, not just predefined widget actions.
Cricket analogy: Just as a broadcaster adds a graphical scoreboard overlay on top of the raw video feed to make it watchable for fans, package require Tk adds a graphical widget layer on top of a plain Tcl script's console output.
#!/usr/bin/env tclsh
# hello.tcl - a first Tcl script with input and a proc
proc greet {name} {
puts "Hi, $name! Welcome to Tcl."
}
puts -nonewline "What is your name? "
flush stdout
gets stdin userName
greet $userName
foreach n {1 2 3} {
puts "Countdown: $n"
}#!/usr/bin/env wish
# hello_gui.tcl - the same greeting, as a small Tk GUI
label .l -text "Enter your name:"
entry .e -textvariable name
button .b -text OK -command { puts "Hello, $name!" }
bind .e <Return> { puts "Hello, $name!" }
pack .l .e .b -padx 10 -pady 5Run console scripts like hello.tcl with tclsh and GUI scripts like hello_gui.tcl with wish (or add package require Tk at the top and keep using tclsh). Mixing them up isn't fatal — tclsh can load Tk on demand — but using wish for GUI scripts avoids needing that extra line.
puts "text"writes a string plus a trailing newline to standard output;puts -nonewlinesuppresses it.#starts a comment only where a new command is expected, not anywhere in the middle of a line.proc name {args} {body}defines a reusable command; it is then called just like a built-in command.if/elseif/elsehandle branching, andforeach/while/forhandle iteration, using the same brace-body convention.gets stdin linereads a line of user input;$argv,$argc, and$argv0give access to command-line arguments.package require Tk(automatic underwish) unlocks widgets likelabel,entry, andbutton, laid out withpack.bindattaches a script to a specific event, such as<Return>, generalizing Tk's event handling beyond simple button clicks.
Practice what you learned
1. What does `puts "Hello, world!"` do?
2. Where must a `#` appear for Tcl to treat it as starting a comment?
3. How do you call a procedure defined with `proc greet {name} { ... }`?
4. What does `$argc` represent in a Tcl script?
5. What must be true before you can create Tk widgets like `button` in a script run with `tclsh`?
Was this page helpful?
You May Also Like
Tcl Syntax and Variables
How Tcl's command-word syntax, substitution rules ($, [], {}), and the `set` command work together to define and use variables.
Tcl Data Types and Lists
How Tcl's 'everything is a string' model supports lists, arrays, and dictionaries, and the core commands for building and manipulating them.
Installing Tcl and Running Scripts
How to install Tcl/Tk on Linux, macOS, and Windows, verify the installation, and run scripts using tclsh and wish.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics