0

I'm trying to see if I can redirect the output of tclsh to a specific file via >

for example

puts "123" > test.log

set a 123 > test.log

procTest {a b} > test.log

No good ideas at the moment.

piper
  • 79
  • 4
  • What do you want exactly? `puts` has output but an empty result, and `set` has no output and (usually) a non-empty result. – Donal Fellows Apr 28 '23 at 08:04
  • Are you bothered by the output in an **interactive** tclsh session? – glenn jackman Apr 28 '23 at 12:35
  • @glenn I would like to complete this function, which is very common in linux, and I am indeed not particularly familiar with tcl. – piper Apr 30 '23 at 06:41
  • @Donal I may not have expressed it correctly, I want to redirect the output to the specified file via the > symbol, usually for commands that have output. – piper Apr 30 '23 at 06:44

2 Answers2

0

There's no need to guess, just read the documentation:

https://wiki.tcl-lang.org/page/Tcl+Tutorial+Lesson+24

and

https://www.tcl-lang.org/man/tcl8.6/TclCmd/contents.htm

Colin Macleod
  • 4,222
  • 18
  • 21
0

Redirection with > filename is only supported by exec (and open |...; that uses the same engine as exec). It's not a general feature of the wider language, and isn't ever going to be (> and < are used for other purposes by well known packages.)

For commands that print output, you can redirect with a variation on my answer to this question:

oo::class create Redirect {
    variable f
    constructor {filename} {
        # Note that this is a binary file; conversion to bytes done by stdout channel
        set f [open $filename wb]
    }
    method initialize {handle mode} {
        if {$mode ne "write"} {error "can't handle reading"}
        return {finalize initialize write}
    }
    method finalize {handle} {
        close $f
    }

    method write {handle bytes} {
        puts -nonewline $f $bytes
        # Return the empty string, as we are swallowing the bytes
        return ""
    }
}

You'd use it like this:

# Attach the redirect
chan push stdout [Redirect new outputfile.txt]

# Call code to do the writes here
puts "this is a test; hello world!"

# Stop redirecting
chan pop stdout

This won't work for use of @stdout in exec (or open |...). Making those work will require the use of dup from the TclX package.

package require Tclx

# Do the redirection
set saved [dup stdout]
set f [open outputfile.txt]
dup $f stdout

# Generate the output
puts "this is a test; hello world!"

# Restore
dup $saved stdout
close $saved
close $f

When doing things like this, it's probably best to use a helper procedure:

proc redirectStdout {filename body} {
    set saved [dup stdout]
    set f [open $filename]
    dup $f stdout
    try {
        uplevel 1 $body
    } finally {
        dup $saved stdout
        close $saved
        close $f
    }
}
# proc redirectStdout {filename body} {
#     chan push stdout [Redirect new $filename]
#     try {
#         uplevel 1 $body
#     } finally {
#         chan pop stdout
#     }
# }

redirectStdout outputfile.txt {
    puts "this is a test; hello world!"
}
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215