Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

executing 'cat' command from tcl script 1

Status
Not open for further replies.

huskers

Programmer
Jan 29, 2002
75
US
I am getting errors when trying to run the exec from the script.

set dir /a/ab
exec cat $dir/04222002M? | sort -T. | uniq > M

the error I am getting is:
cat: cannot open /a/ab/06222002M?

Can any one point me what might be wrong here. any help is appreciated

Thanks
 
Maybe the file really does'nt exist.
Can you add this statement between the other two and watch the result?
Code:
puts [glob  $dir/04222002M?]

This statement should show the name of the files corresponding to $dir/04222002M?.

Good luck!

ulis
 
thanks for the response, when i used the puts [glob $dir/04222002M?] statement it showed me all the files that were present but the exec command gives me the same error:

cat: cannot open /a/ab/06222002M?

Is it the way that TCL interprets???
 
The problem might (and I stress, might) be in the Tcl interpretation of numbers that start with "0" as octal. Bob Rashkin
rrashkin@csc.com
 
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:

Code:
exec cat $dir/04222002M?

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
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top