Tcl · Module 15
argv, argc and argv0: Command-Line Arguments
A program that always reads the same hard-coded file is a snippet. Taking the filename from the command line is the first thing that makes it a tool someone else can use.
Foundation16 min readtclargvargccommand-linescriptsusage
Part I · Module 15 · Chapter 15.2 · argv, argc and argv0: Command-Line Arguments
A script with the input filename written inside it can only ever do one job. Reading the filename from the command line is what turns it into something another engineer can point at their own data.
Tcl gives you three global variables for this, set before your script runs.
1. The three variables
| Variable | Holds |
|---|---|
argv0 | the script, as it was named on the command line |
argv | a list of the arguments that came after the script |
argc | how many items are in argv |
The important word is in the second row: argv holds only what came after the script name.
2. Watching all three
# args.tcl
puts "argv0 = $argv0"
puts "argc = $argc"
puts "argv = $argv"
set i 0
foreach a $argv {
puts " argv\[$i\] = '$a'"
incr i
}Three invocations:
$ tclsh args.tcl
argv0 = args.tcl
argc = 0
argv =
$ tclsh args.tcl input.txt
argv0 = args.tcl
argc = 1
argv = input.txt
argv[0] = 'input.txt'
$ tclsh args.tcl -verbose -out r.txt input.txt
argv0 = args.tcl
argc = 4
argv = -verbose -out r.txt input.txt
argv[0] = '-verbose'
argv[1] = '-out'
argv[2] = 'r.txt'
argv[3] = 'input.txt'Three things to read out of that:
tclshis not inargv0.argv0isargs.tcl. The interpreter you invoked is not part of your program's arguments.argccounts words, not options. The last run passed what a human would call two options and one file, andargcis 4 — because-outandr.txtare separate words. Separating those back into options is Chapter 15.3.- With no arguments,
argvis empty and prints as nothing. It is an empty list, not an error and not unset.
3. argc or llength?
Both work. argc is set for you, and [llength $argv] asks the list directly:
if {[llength $argv] < 1} { ... }Prefer llength $argv. The two agree at the start, but the moment you consume arguments — which is what an option parser does, usually with set argv [lrange $argv 1 end] — only llength keeps telling the truth. argc is a snapshot taken before your script ran, and nothing updates it.
4. argv is a list, and that matters
Here is why you should never treat argv as a string. Pass a filename containing a space:
# safe.tcl
puts "argv as a string : '$argv'"
puts ""
puts "treating it as TEXT:"
puts " split \$argv \" \" -> [llength [split $argv " "]] pieces: [split $argv " "]"
puts ""
puts "treating it as a LIST:"
puts " llength \$argv -> [llength $argv]"
puts " lindex \$argv 0 -> '[lindex $argv 0]'"
puts " lindex \$argv 1 -> '[lindex $argv 1]'"
puts ""
puts "does the file exist under that name?"
puts " file exists [lindex $argv 0] -> [file exists [lindex $argv 0]]"$ tclsh safe.tcl "my data.txt" second.txt
argv as a string : '{my data.txt} second.txt'
treating it as TEXT:
split $argv " " -> 3 pieces: \{my data.txt\} second.txt
treating it as a LIST:
llength $argv -> 2
lindex $argv 0 -> 'my data.txt'
lindex $argv 1 -> 'second.txt'
does the file exist under that name?
file exists my data.txt -> 1The rule is the one from Chapter 14.8 §2: a space makes a value two list elements, so use list commands on lists. For argv that means llength, lindex, lrange, lassign, and foreach — never split, string range, or a regular expression.
This is not a rare case. Filenames with spaces are normal on every desktop platform, and a tool that mangles them is a tool people stop using.
5. A usage check
A program given the wrong arguments should say so and stop. The whole pattern is five lines:
# usage.tcl
if {[llength $argv] < 1} {
puts stderr "usage: $argv0 <input-file>"
exit 2
}
set input [lindex $argv 0]
puts "would process: $input"$ tclsh usage.tcl
usage: usage.tcl <input-file>
exit status: 2
$ tclsh usage.tcl readings.txt
would process: readings.txt
exit status: 0Four decisions are packed into those five lines, and all four are deliberate:
- The message goes to
stderr. It is a diagnostic, not output. If someone runstclsh usage.tcl > results.txt, the error still reaches them instead of being written into the results file. This is Chapter 14.9 §2 applied. - The exit status is non-zero. A caller — a shell script, a Makefile, a scheduler — decides what to do next from that number. Chapter 15.4 covers why 2 rather than 1.
- It checks before it reads.
[lindex $argv 0]on an empty list returns an empty string rather than raising, so without the guard the program would carry on with an empty filename and fail later with a confusing message about"". - The message names the program and shows the shape.
usage: usage.tcl <input-file>tells the reader what to type.wrong argumentsdoes not.
6. Several inputs
A tool that takes one file should usually take several, and with a list this costs nothing:
if {[llength $argv] == 0} {
puts stderr "usage: [file tail $argv0] INPUT..."
exit 2
}
foreach path $argv {
puts "processing $path"
}foreach over argv handles one file, five files, or a shell glob that expanded to two hundred — and each one arrives as a single element even if it contains spaces.
7. Where this is going
By the end of this module the capstone program is invoked like this:
$ tclsh bin/report-tool.tcl -verbose -limit 30 data/readings.txtEverything after the script name arrives in argv as five words. This chapter is how you receive them; the next is how you make sense of them.
8. Exercises
Exercise 1. For tclsh report.tcl -v input.txt, what are argv0, argc and argv?
Exercise 2. Why is the first real argument [lindex $argv 0] and not [lindex $argv 1]?
Exercise 3. Why prefer [llength $argv] over $argc?
Exercise 4. puts $argv shows {my data.txt} second.txt. Where did the braces come from, and is the filename wrong?
Exercise 5. A script with no usage check is run with no arguments. set input [lindex $argv 0] does not raise. What happens instead, and why is that worse?
Exercise 6. Write a guard that requires at least one argument, prints a usage line, and exits with a status a caller can test.
Where this fits
Part of the Tcl curriculum.
