Skip to content
VLSI Mentor

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

VariableHolds
argv0the script, as it was named on the command line
argva list of the arguments that came after the script
argchow 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ 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:

  • tclsh is not in argv0. argv0 is args.tcl. The interpreter you invoked is not part of your program's arguments.
  • argc counts words, not options. The last run passed what a human would call two options and one file, and argc is 4 — because -out and r.txt are separate words. Separating those back into options is Chapter 15.3.
  • With no arguments, argv is 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# 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]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ 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 -> 1

The 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# usage.tcl
if {[llength $argv] < 1} {
    puts stderr "usage: $argv0 <input-file>"
    exit 2
}
set input [lindex $argv 0]
puts "would process: $input"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ tclsh usage.tcl
usage: usage.tcl <input-file>
exit status: 2

$ tclsh usage.tcl readings.txt
would process: readings.txt
exit status: 0

Four 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 runs tclsh 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 arguments does not.

6. Several inputs

A tool that takes one file should usually take several, and with a list this costs nothing:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ tclsh bin/report-tool.tcl -verbose -limit 30 data/readings.txt

Everything 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.