How to suppress a proc's return value in tcl prompt

后端 未结 3 997
清歌不尽
清歌不尽 2020-12-21 09:07

I\'m relatively new in TCL, in TCL prompt, when we invoke a proc with some return value, the proc\'s return value is echoed back by tcl. Is there a way to stop it (without a

相关标签:
3条回答
  • 2020-12-21 09:34

    Use tcl_interactive variable to enable the return of of the value, although I'm not sure where this would be useful...

    proc a {} {
        puts "hello"
        if { [info exist tcl_interactive] } {
            return {};
        } else {
            return 34;
        }
    } 
    
    0 讨论(0)
  • 2020-12-21 09:35

    You could make an empty procedure in .tclshrc...

    proc void {} {}
    

    ...and when you don't need a return value, end the line with ;void.

    0 讨论(0)
  • 2020-12-21 09:47

    The interactive shell code in tclsh and wish will print any non-empty result. To get nothing printed, you have to have the last command on the “line” produce an empty result. But which command to use?

    Many commands will produce an empty result:

    if 1 {}
    subst ""
    format ""
    

    However, the shortest is probably:

    list
    

    Thus, you could write your code like:

    a;list
    

    Of course, this only really becomes useful when your command actually produces a large result that you don't want to see. In those cases, I often find that it is most useful to use something that measures the size of the result, such as:

    set tmp [something_which_produces a_gigantic result]; string length $tmp
    

    The most useful commands I find for that are string length, llength and dict size.


    If you absolutely must not print the result of the command, you have to write your own interactive loop. There are two ways to do this, depending on whether you are running inside the event loop or not:

    Without the event loop

    This simplistic version just checks to see if the command name is in what the user typed. It's probably not a good idea to arbitrarily throw away results otherwise!

    set accum ""
    while {[gets stdin line] >= 0} {
        append accum $line "\n"
        if {[info complete $accum]} {
            if {[catch $accum msg]} {
                puts stderr $msg
            } elseif {$msg ne "" && ![string match *TheSpecialCommand* $accum]} {
                puts $msg
            }
            set accum ""
        }
    }
    

    With the event loop

    This is just handling the blocking IO case; that's the correct thing when input is from a cooked terminal (i.e., the default)

    fileevent stdin readable handleInput
    set accum ""
    proc handleInput {} {
        global accum
        if {[gets stdin line] < 0} {
            exit; # Or whatever
        }
        append accum $line "\n"
        if {[info complete $accum]} {
            if {[catch {uplevel "#0" $accum} msg]} {
                puts stderr $msg
            } elseif {$msg ne "" && ![string match *TheSpecialCommand* $accum]} {
                puts $msg
            }
            set accum ""
        }
    }
    vwait forever; # Assuming you're not in wish or have some other event loop...
    

    How to detect the command is being executed

    The code above uses ![string match *TheSpecialCommand* $accum] to decide whether to throw away the command results, but this is very ugly. A more elegant approach that leverages Tcl's own built-in hooks is to use an execution trace to detect whether the command has been called (I'll just show the non-event-loop version here, for brevity). The other advantage of this is that it is simple to extend to suppressing the output from multiple commands: just add the trace to each of them.

    trace add execution TheSpecialCommand enter SuppressOutput
    proc SuppressOutput args {
        # Important; do not suppress when it is called inside another command
        if {[info level] == 1} {
            set ::SuppressTheOutput 1
        }
    }
    
    # Mostly very similar from here on
    set accum ""
    while {[gets stdin line] >= 0} {
        append accum $line "\n"
        if {[info complete $accum]} {
            set SuppressTheOutput 0;                       # <<<<<< Note this!
            if {[catch $accum msg]} {
                puts stderr $msg
            } elseif {$msg ne "" && !$SuppressTheOutput} { # <<<<<< Note this!
                puts $msg
            }
            set accum ""
        }
    }
    

    To be clear, I wouldn't ever do this in my own code! I'd just suppress the output manually if it mattered.

    0 讨论(0)
提交回复
热议问题