Parse Command Line in a Tcl Script

The Problem

I am writing script in Tcl, but want an easy and simple way to parse command line parameter. For example, the user might invoke my script as:

	tclsh myscript.tcl -server testserver15 -user testuser3

The Solution

This is one way to solve the problem. It does not mean to be the only one, but an easy and simple one. The solution is to use a library package called cmdline which comes with most Tcl installations. Below is a sample script I wrote to demonstrate this technique.

The Sample Script

To demonstrate the solution, I created a sample script called parse_argv.tcl with the following contents:

package require cmdline

# Show argv before processing
puts "Before, argv = '$argv'"

# Process the command line
set parameters {
    {server.arg ""   "Which server to test"}
    {port.arg   5551 "Port to send test cmd"}
    {user.arg   ""   "Login name"}
    {debug           "Output extra debug info"}
}
array set arg [cmdline::getoptions argv $parameters]

# Verify required parameters
set requiredParameters {server user}
foreach parameter $requiredParameters {
    if {$arg($parameter) == ""} {
        puts stderr "Missing required parameter: -$parameter"
        exit 1
    }
}

# Displays the arguments
puts ""
parray arg
puts ""

# Show argv after processing
puts "After, argv = '$argv'"

Explanation

  • Line 7 – Define the command line parameters and their defaults. If a parameter has an .arg suffix, then it must be followed by a value. A parameter without the .arg suffix is a simple boolean (0 or 1) parameter. Please note that the parameter names are case sensitive, so -server is not the same as -Server.For more information, please consult the documentation for cmdline.
  • Line 8 – A call to cmdline::getoptions does all the works. Please note:
    1. If the user supplies a parameter not that getoptions does not recognize, it will display a usage and throw an error, which will cause the script to exit prematurely.
    2. If getoptions encounters a ‘–‘ (double dashes) on the command line, it will delete that token and stop processing. This behavior is consistent with many Unix’s commands.
    3. The contents of argv will be modified. That is why we pass argv instead of $argv to getoptions.
    4. getoptions returns a list of keyword/value such as {server “” port 5551 …}. The array set turns this list into an array.
  • Line 30 – After processing the command line, argv contains the left-over. Please take a look at the Sample Runs section for an example of this behavior

Sample Runs

	$ tclsh parse_argv.tcl 
	Before, argv = ''
	Missing required parameter: -server

Invoke the script without specifying the required parameters will cause it to show an error then exit.


	$ tclsh parse_argv.tcl -server testserver15 -user testuser3 extra1 extra2
	Before, argv = '-server testserver15 -user testuser3 extra1 extra2'

	arg(debug)  = 0
	arg(port)   = 5551
	arg(server) = testserver15
	arg(user)   = testuser3

	After, argv = 'extra1 extra2'

In this run, the user specifies all the required parameters and a few extras. Notice:

  • How argv changed after calling getoptions
  • arg(debug) is 0 because the user has not specified a -debug flag in the command line

Conclusion

The cmdline package offers a simple and easy way to parse command line parameters. It should save programmers coding time and sanity. The package is not perfect: it does not check for required parameters, nor does it validate them. In the script, I worked around the first issue by checking for required parameters myself (lines 16 to 22).

To demonstrate the second issue, let’s take a look at the -port parameter. If I require this parameter to be an integer between 5000-5999, I have to write the verification myself.

I hope cmdline to evolve and address these issues. Meanwhile, I am glad to have it under my belt.

6 thoughts on “Parse Command Line in a Tcl Script

  1. Prasenjit

    -Help Err fix

    package require cmdline

    # Show argv before processing
    puts “Before, argv = ‘$argv'”

    # Process the command line
    set parameters {
    {server.arg “” “Which server to test”}
    {port.arg 5551 “Port to send test cmd”}
    {user.arg “” “Login name”}
    {debug “Output extra debug info”}
    }

    if { [catch { array set arg [cmdline::getoptions argv $parameters] } ERR ]} {
    puts $ERR
    exit -1
    }

    # Verify required parameters
    set requiredParameters {server user}
    foreach parameter $requiredParameters {
    if {$arg($parameter) == “”} {
    puts stderr “Missing required parameter: -$parameter”
    exit 1
    }
    }

    # Displays the arguments
    puts “”
    parray arg
    puts “”

    # Show argv after processing
    puts “After, argv = ‘$argv'”

  2. John

    @ “The package is not perfect: it does not check for required parameters”
    It is not intended to! As the name suggests: getopts parses _options_. If parameters are _required_ they are not options (and should just be positional args without a -tag).

  3. wedding favours uk

    I am really enjoying the theme/design of your site. Do you ever run into any web browser compatibility problems?

    A couple of my blog readers have complained about my blog not operating correctly in Explorer but looks great in Firefox.
    Do you have any tips to help fix this problem?

  4. Hai Post author

    Hello Wedding Favours UK. My “website” is just a WordPress blog, which I applied from wordpress.com for free. I am not a web designer, so I don’t know how to fix your problem. You might want to try stackoverflow.com.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s