tclio-redirection

Tcl, tee stderr to a file


I'm writing a Tcl 8.6 script that needs to be portable across both Windows and Linux.

We want to capture the content written to stderr by the rest of the program, and simultaneously write it to a file (like what tee is doing).

My environment cannot install any external package, we need to implement it by our own.

AI gives me this:

chan create write TeeFilter {
    variable log
    constructor {path} {
        set log [open $path w]
        chan configure $log -buffering none
    }
    method write {data} {
        puts -nonewline $chan $data
        puts -nonewline $log $data
    }
    method finalize {} {
        close $log
    }
}
chan push stderr [TeeFilter new "captured_stderr.txt"]

It does not work.

ERROR : ERR (1) : wrong # args: should be "chan create mode cmdprefix"

I've tried many AI suggestions, but none worked. How can I implement this?


Solution

  • I have noticed that AI is not very proficient in Tcl.

    I published a working implementation of tee-like functionality on the Tcl wiki a few years ago: https://wiki.tcl-lang.org/page/Tee

    namespace eval tee {
        variable methods {initialize finalize write}
        namespace ensemble create -subcommands {replace append channel} \
          -unknown [namespace current]::default
        namespace ensemble create -command transchan -parameters fd \
          -subcommands $methods
    }
    
    proc tee::default {command subcommand args} {
        return [list $command replace $subcommand]
    }
    
    proc tee::channel {chan fd} {
        chan push $chan [list [namespace which transchan] $fd]
        return $fd
    }
    
    proc tee::replace {chan file} {
        return [channel $chan [open $file w]]
    }
    
    proc tee::append {chan file} {
        return [channel $chan [open $file a]]
    }
    
    proc tee::initialize {fd handle mode} {
        variable methods
        return $methods
    }
    
    proc tee::finalize {fd handle} {
        close $fd
    }
    
    proc tee::write {fd handle buffer} {
        puts -nonewline $fd $buffer
        return $buffer
    }
    

    Use as: tee stderr captured_stderr.txt