1

I am running a bunch of functions. Each of them outputs a lot of text to stdout which prevents me from quickly checking the results. Is there any easy way to stop output going to the stdout channel? Thanks

AturSams
  • 7,568
  • 18
  • 64
  • 98

2 Answers2

2

If the functions are just writing to stdout for logging purposes and you want to throw all that stuff away, and they aren't wanting to write to disk or a socket or any other kind of channel, the simplest method is this:

rename puts original_puts
proc puts args {}   ;# A do-nothing procedure!

To convert back to normal operation:

rename puts {}
rename original_puts puts

Be aware that this will cause problems if the wrapped code has an error in it unless you are careful. Here's a wrapped “careful” version (for Tcl 8.5):

proc replacement_puts args {}
proc silentEval {script} {
    rename puts original_puts
    interp alias {} puts {} replacement_puts
    catch [list uplevel 1 $script] msg opts
    rename puts {}
    rename original_puts puts
    return -options $opts $msg
}

Then you just do this:

silentEval {
    call-noisy-function-A
    call-noisy-function-B
    ...
}

If you've got code that wants to write to files (or sockets or …) then that's possible via a more complex replacement_puts (which can always use the original_puts to do the dirty work).

If those functions are writing to stdout from the C level, you're much more stuck. You could do close stdout;open /dev/null to direct the file descriptor to a sink, but you wouldn't be able to recover from that easily. (There's a dup in the TclX package if that's necessary.) Try the simple version above if you can first.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
0

The only good way to prevent output to stdout/stderr is to remove (in some way) the stdout/stderr channel from the interpreter you are executing the script in, because there are many ways to write things to a channel (including, but not limited to puts, chan puts and fcopy)

I suggest creating a new safe interp and transfer the channel to this interp, call the script, and transfer the channel back. After that you might choose to delete the interp or reuse it for similar purposes.

proc silentEval {script} {
    set i [interp create -safe]
    interp transfer {} stdout $i
    catch [list uplevel 1 $script] msg opts
    interp transfer $i stdout {}
    interp delete $i
    dict incr $opts -level
    return -options $opts $msg
}
Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73