Как подавить возвращаемое значение proc в приглашении tcl

Я относительно новичок в TCL, в приглашении TCL, когда мы вызываем proc с некоторым возвращаемым значением, возвращаемое значение proc возвращается в tcl. Есть ли способ остановить его (не затрагивая путы или аналогичные функции) в качестве примера

bash$ tclsh
% proc a {} { puts  "hello"; return 34; }
% a
hello
34
%

Теперь, как я могу подавить 34 прихода на экран? Любая помощь приветствуется.

Обновление: на самом деле proc является частью другого инструмента, раньше у него не было возвращаемого значения, но теперь условно он может возвращать значение. он может быть вызван из скрипта, и проблем не будет (как отметил Брайан). и он может быть вызван из интерактивной подсказки, после чего после всех необходимых выходных данных возвращаемое значение печатается без необходимости. Итак, 1) у меня нет возможности изменить tclshrc пользователя 2) существующие скрипты должны продолжать работать. И кажется странным, что при каждом вызове proc после всех необходимых выходных данных печатается число. Для пользователя это ненужная информация, если он не уловил ценность и не хочет что-то делать. Поэтому я хотел, чтобы значение было доставлено пользователю, но без печати в подсказку / пользовательский интерфейс (надеюсь, мне понятно)

3 ответа

Интерактивный код оболочки в tclsh а также wish напечатает любой непустой результат. Чтобы ничего не печатать, вам нужно, чтобы последняя команда в "строке" выдавала пустой результат. Но какую команду использовать?

Многие команды приведут к пустому результату:

if 1 {}
subst ""
format ""

Однако самое короткое, вероятно, это:

list

Таким образом, вы можете написать свой код так:

a;list

Конечно, это действительно становится полезным только тогда, когда ваша команда на самом деле дает большой результат, который вы не хотите видеть. В этих случаях я часто нахожу, что наиболее полезно использовать что-то, что измеряет размер результата, например:

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

Самые полезные команды, которые я нахожу для этого: string length, llength а также dict size,


Если вам абсолютно не нужно печатать результат команды, вы должны написать свой собственный интерактивный цикл. Есть два способа сделать это, в зависимости от того, работаете ли вы в цикле обработки событий или нет:

Без цикла событий

Эта упрощенная версия просто проверяет, соответствует ли имя команды тому, что набрал пользователь. В противном случае произвольно выбрасывать результаты - не очень хорошая идея!

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

С циклом событий

Это просто обработка блокирующего случая ввода-вывода; это правильно, когда ввод с готового терминала (то есть по умолчанию)

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...

Как обнаружить, что команда выполняется

Код выше использует ![string match *TheSpecialCommand* $accum] решить, следует ли выбрасывать результаты команды, но это очень некрасиво. Более элегантный подход, использующий собственные встроенные хуки Tcl, заключается в использовании трассировки выполнения для определения того, была ли вызвана команда (для краткости я просто покажу здесь версию без цикла обработки событий). Другое преимущество этого заключается в том, что его легко распространить на подавление вывода из нескольких команд: просто добавьте трассировку к каждой из них.

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

Чтобы было ясно, я бы никогда не сделал это в своем собственном коде! Я бы просто подавил вывод вручную, если бы он имел значение.

Вы можете сделать пустую процедуру в.tclshrc...

proc void {} {}

... и когда вам не нужно возвращаемое значение, завершите строку ;void,

Используйте переменную tcl_interactive, чтобы включить возврат значения, хотя я не уверен, где это было бы полезно...

proc a {} {
    puts "hello"
    if { [info exist tcl_interactive] } {
        return {};
    } else {
        return 34;
    }
} 
Другие вопросы по тегам