I/O Operations in Tcl
Master input and output in Tcl - formatted console output, reading from stdin, and file channels with open, read, gets, puts, and close
Input and output in Tcl revolve around a single elegant abstraction: the channel. The console, files, pipes, and sockets are all channels, and the same small set of commands—puts, gets, read, and close—works on all of them. Once you learn to read and write a file, you already know how to talk to a network socket.
This uniformity is a direct consequence of Tcl’s “everything is a string” philosophy. Data flowing through a channel is just text (unless you ask for binary mode), so there’s no distinction between “serializing” data and simply writing it. Combined with Tcl’s event-driven heritage, channels can even be read asynchronously with fileevent—the same mechanism that powers Tk GUIs and network servers.
In this tutorial you’ll go beyond the puts you met in Hello World: formatting output precisely, reading user input from stdin, writing and reading files in several modes, and handling I/O errors gracefully with catch.
Formatted Console Output
You already know puts writes a line to standard output. It has more tricks: it can suppress the trailing newline, write to any channel (including stderr), and pair with the format command for printf-style precision.
Create a file named io_console.tcl:
| |
The first argument to format is a template; %s, %d, %f, %x, and friends are filled from the remaining arguments. Because format simply returns a string, you can use it anywhere a string is expected—not just in puts.
Reading from Standard Input
Standard input is the pre-opened channel stdin. The gets command reads one line from a channel; with two arguments it stores the line in a variable and returns the character count (or -1 at end of file).
Create a file named io_input.tcl:
| |
Two details matter here. First, flush stdout forces the prompt to appear before the program blocks waiting for input—output to stdout is line-buffered, and the prompt has no newline. Second, [gets stdin] with one argument returns the line directly, which is convenient for simple scripts; the two-argument form (gets stdin name) is preferred inside loops because its return value signals end of file.
Because everything in Tcl is a string, no conversion step is needed before doing arithmetic on $born—expr interprets the string as a number when the context demands it.
File I/O with Channels
Files use the same commands as the console. The open command returns a channel handle, which you pass to puts, gets, or read, and finally to close. The second argument to open is the access mode: r to read, w to write (truncating), and a to append.
Create a file named io_files.tcl:
| |
The while {[gets $in line] >= 0} idiom is the standard Tcl pattern for processing a file line by line without loading it all into memory. The catch command traps the error raised when open fails and stores the message in err, letting the script recover instead of dying. Finally, the file command family (file exists, file delete, file size, file mkdir, and many more) handles filesystem operations that don’t involve reading content.
Running with Docker
| |
Note the -i flag on the second command—it connects your terminal’s stdin to the container so gets stdin can read what you type.
Expected Output
Running io_console.tcl (stderr and stdout both appear in the terminal):
A plain line from puts
These two pieces... join on one line
Tcl appeared in 1988
Pi is roughly 3.1416
Hex: ff Octal: 10 Padded: 00042
Diagnostics go to standard error
Running io_input.tcl (a sample session; entering Ada and 1990):
What is your name? Ada
What year were you born? 1990
Hello, Ada!
You turn 36 this year.
Running io_files.tcl:
--- Whole file ---
First entry
Second entry
Third entry
--- Line by line ---
1: First entry
2: Second entry
3: Third entry
Could not open file: couldn't open "missing.txt": no such file or directory
File exists after delete: 0
Key Concepts
- Everything is a channel -
stdin,stdout,stderr, files, pipes, and sockets all use the same commands:puts,gets,read, andclose. putswrites,getsreads lines - Both take an optional channel argument;putsdefaults tostdout, andgetsreturns-1at end of file, which drives the standardwhile {[gets $ch line] >= 0}loop.formathandles precision - Printf-style templates (%s,%d,%8.4f,%05d) return a string you can use anywhere, not just for printing.- Flush prompts before reading - Stdout is buffered, so call
flush stdoutafter aputs -nonewlineprompt or the user may never see it. openmodes mirror C -rreads,wtruncates and writes,aappends;openreturns a handle that must eventually be passed toclose.readslurps,getsiterates - Useread $chfor small files you want whole, and agetsloop for large files or record-by-record processing.- Trap I/O errors with
catch- Failed opens raise Tcl exceptions;catch {open ...} errcaptures the message so your script can recover. - The
filecommand manages the filesystem -file exists,file delete,file size, and relatives cover metadata and manipulation without opening a channel.
Running Today
All examples can be run using Docker:
docker pull efrecon/tcl:latest
Comments
Loading comments...
Leave a Comment