Most commands (such as "cat" and "ls"

don't perform wildcard expansion on file names; instead they rely on the shell (e.g., sh, csh, ksh, etc.) to do that for them and to pass them the different file names as separate arguments.
However, the Tcl interpreter doesn't perform wildcard expansion. And the Tcl
exec command doesn't start a separate shell, but instead executes the command(s) you specify directly. So when you execute:
Tcl starts the "cat" program and passes it the value of
dir concatenated with "04222002M?" as the file name. And obviously, "cat" isn't finding this un-expanded file name. (I'm omitting the rest of your process pipeline in these examples just to focus on the problem area.)
To force Tcl to perform wildcard expansion, you need to use its
glob command.
glob takes one or more file name patterns and returns a
list of the files that match those patterns. Also note that
glob generates a Tcl error condition if it finds no files that match the pattern(s), unless you use the
glob -nocomplain option (in which case it simply returns an empty list).
This is why
ulis was hinting at using the following:
Code:
exec cat [glob $dir/04222002M?]
However, this won't work either. Like I said earlier,
glob returns a
list of all files that match the pattern.
exec then takes this list
as a single argument and passes it to the "cat" command. So -- unless there's just a single file that matched the pattern -- "cat" is going to see the big string of all the file names as a single argument and interpret it as a single file name. For example, a single file with the name "/a/ab/06222002M1 /a/ab/06222002M2 /a/ab/06222002M3".
So what do we do now? Well, we need to use another Tcl command,
eval, to help break down the list structure.
eval concatenates all of its arguments, just like Tcl's
concat command, and then executes the resulting list as a Tcl command string. (Some people find it easier to think of
eval as breaking down one layer of list structure in each of its arguments, and then executing the result.)
So, the answer is to use:
Code:
eval exec cat [glob $dir/04222002M?]
The
glob command executes and gives us something like this:
Code:
eval exec cat "/a/ab/06222002M1 /a/ab/06222002M2 /a/ab/06222002M3"
Then
eval concatenates everything together. The first two arguments to
eval simply look like 1-element lists, and the last argument looks like a 3-element list, so
eval generates a 5-element list that looks like:
Code:
exec cat /a/ab/06222002M1 /a/ab/06222002M2 /a/ab/06222002M3
And this is the result that
eval finally executes. And now everything works okay.
As a final exercise, let me show you one way you can do this all in Tcl. But note that the final output might not be the same because of differences in the way the Unix "sort" and Tcl's
lsort commands work. But perhaps it will do the job for you, and it does have the advantage of being about 4 times faster.
Code:
# Split the contents of each file into a
# list of lines, and concatenate them all
# together. Use "file join" for safe pathname
# generation.
set contents [list]
foreach file [glob -nocomplain [file join $dir 04222002M?]] {
set fid [open $file r]
eval lappend contents [split [read $fid] "\n"]]
close $fid
}
# Use lsort -unique to sort the contents and
# throw out duplicates. (I believe that the
# -unique option was introduced in Tcl 8.3.)
# Then join the sorted list of lines using
# newlines, and write the result to our output
# file.
set fid [open "M" w]
puts $fid [join [lsort -unique $contents] "\n"]
close $fid
- Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax