piper
piper

Reputation: 87

How to use > to redirect output in tclsh

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.

Upvotes: 0

Views: 416

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137577

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!"
}

Upvotes: 0

Colin Macleod
Colin Macleod

Reputation: 4382

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

Upvotes: 0

Related Questions