2

I'm trying to create a tcl proc, which is passed a shell command as argument and then opens a temporary file and writes a formatted string to the temporary file, followed by running the shell command in background and storing the output to the temp file as well.

Running the command in background, is so that the proc can be called immediately afterwards with another arg passed to it, writing to another file. So running a hundred such commands should not take as long as running them serially would do. The multiple temp files can finally be concatenated into a single file.

This is the pseudocode of what I'm trying to do.

proc runthis { args }  
{ 
    set date_str [ exec date {+%Y%m%d-%H%M%S} ]
    set tempFile ${date_str}.txt
    set output [ open $tempFile a+ ]
    set command [concat exec $args]
    puts $output "### Running $args ... ###"   

    << Run the command in background and store output to tempFile >>
}

But how do I ensure the background'ing of the task is done properly? What would need to be done to ensure that the multiple temp files get closed properly?

Any help would be welcome. I'm new at tcl and finding to get my mind around this. I read about using threads in tcl but I'm working with an older version of tcl which doesn't support threading.

div310
  • 43
  • 1
  • 4
  • First off, the open brace of the procedure body has to go on the same logical line as the `proc` itself (well, there can be quoted newlines in between, e.g. in the argument list or backslashed, but that's a refinement that most people don't bother with). – Donal Fellows Dec 17 '12 at 11:47
  • Secondly, you can use `clock format` and `clock seconds` to do the work of `exec date`. Mind you, to keep output from different runs separate you also need a sequence number (in case two runs start within the same second, of course). – Donal Fellows Dec 17 '12 at 11:50
  • Consider using less lame approach to creating temporary files. [This wiki page](http://wiki.tcl.tk/772) has a nice summary of options (`file tempname` since 8.6 or `mkstemp(3)`-emulating code; as a personal experience, I find Stu's version to be just OK for older Tcls). – kostix Dec 17 '12 at 22:33

1 Answers1

1

How about:

proc runthis { args }  { 
    set date_str [clock format [clock seconds] -format {+%Y%m%d-%H%M%S}]
    set tempFile ${date_str}.txt
    set output [ open $tempFile a+ ]
    puts $output "### Running $args ... ###"   
    close $output

    exec {*}$args >> $tempFile &
}

See http://tcl.tk/man/tcl8.5/TclCmd/exec.htm

Since you seem to have an older Tcl, replace

    exec {*}$args >> $tempFile &

with

    eval exec [linsert $args 0 exec] >> $tempFile &
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • You also need a way to detect when the pipeline has finished. Luckily, the result of a background `exec` is the list of process IDs of the spawned subprocesses… – Donal Fellows Dec 17 '12 at 14:05
  • I get this error "extra characters after close-brace" when I use the command: exec {*}$args >> $tempFile & – div310 Dec 17 '12 at 17:10
  • In this case, what do we need to do once the pipeline has finished? do we need to close/flush something? Also if exec returns the process id, how do I retrieve this? – div310 Dec 17 '12 at 17:13
  • `set pid [exec ...]` - Simple command substitution. If your program/script doesn't need to to anything after the subprocess has been finished, then you are fine. If you get the error "extra characters after close-brace" then you are probably using an old Tcl version (<8.5) The `{*}` word expansion has been added with Tcl 8.5 – Johannes Kuhn Dec 17 '12 at 18:06
  • This line: eval exec [linsert $args exec] >> $tempFile & Gives me this error: -wrong # args: should be "linsert list index element ?element ...?" – div310 Dec 19 '12 at 08:47
  • I concatenated the command, and then ran it through eval. And that works just fine :) – div310 Dec 19 '12 at 10:42
  • At the end of the run, I want to combine all the individual temp files in to one giant file. But at this point I guess I'll need to check if the background processes have all finished execution, or I'll risk getting incomplete data. This is probably where I'll have to use the process ID of the spawned subprocesses right? – div310 Dec 19 '12 at 10:44