2016-01-25 4 views
2

В настоящее время я стреляя следующую командуTCL-Получение Логарифм Exec'd процесса

set pid [exec make &] 

set term_id [wait pid] 

Первая команда будет выполнять Makefile внутри TCL и второй команды будет ждать операции Makefile первой команды для завершения. Первая команда отображает все журналы makefile на stdout. Можно ли хранить все журналы в переменной или файле, когда «&» указан в последнем аргументе exec с использованием перенаправления или любого другого метода?

Если «&» не дано, то мы можем взять выходные данные, используя,

set log [exec make] 

Но если «&» дается тогда команда будет возвращать идентификатор процесса,

set pid [exec make &] 

Так это возможно ли остановить журналы stdout и поместить их в переменную?

ответ

2

Если вы используете Tcl 8.6, вы можете захватить вывод с помощью:

lassign [chan pipe] reader writer 
set pid [exec make >@$writer &] 
close $writer 

Не забудьте прочитать из $reader или подпроцесс будет простаивать. Имейте в виду, что при использовании таким образом выход будет доставлен полностью буферизованным, хотя это более важно при выполнении интерактивной работы. Если вы хотите, чтобы выход был эхом и стандартным, вам нужно сделать так, чтобы ваш сценарий сделал это. Вот простой обработчик для чтения.

while {[gets $reader line] >= 0} { 
    lappend log $line 
    puts $line 
} 
close $reader 

Перед Tcl 8.6, лучше всего было бы создать команду подпроцесс трубопровода:

set reader [open |make] 

Если вам нужен PID, то это может стать немного более сложным:

set reader [open |[list /bin/sh -c {echo $$; exec make}]] 
set pid [gets $reader] 

Да, это довольно уродливо ...


[EDIT]: Вы используете Tk в Tcl 8.5 (так что вам нужна форма конвейера open |…), и поэтому вы хотите сохранить цикл событий. Хорошо. Это точно, для fileevent, но вам нужно думать асинхронно.

# This code assumes that you've opened the pipeline already 
fileevent $reader readable [list ReadALine $reader] 
proc ReadALine {channel} { 
    if {[gets $channel line] >= 0} { 
     HandleLine $line 
    } else { 
     # No line could be read; must be at the end 
     close $channel 
    } 
} 
proc HandleLine {line} { 
    global log 
    lappend log $line;  # Or insert it into the GUI or whatever 
    puts $line 
} 

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

fconfigure $reader -blocking 0 
fileevent $reader readable [list ReadALine $reader] 
proc ReadALine {channel} { 
    if {[gets $channel line] >= 0} { 
     HandleLine $line 
    } elseif {[eof $channel]} { 
     close $channel 
    } 
} 
proc HandleLine {line} { 
    global log 
    lappend log $line 
    puts $line 
} 

Более сложные и разнообразные варианты возможны, но они только действительно необходимо, когда вы имеете дело с ненадежными каналами (например, розетки публичных серверов).


Если вы использовали 8.6, вы могли бы использовать сопрограммы, чтобы этот код выглядел более похожим на прямолинейный код, который я использовал ранее, но это функция, которая строго 8.6 (и более поздняя, ​​когда мы будем делать более поздние версии) только в том случае, если они зависят от без стека.

+0

позвольте мне перефразировать мой вопрос, я использую 8.5 ... Моя операция делает много журналов на stdout и также отображает gui .. Можно ли передать это на переменную? и без «&» мои журналы и графический интерфейс не отображаются в exec? –

+0

С Tcl 8.5 вы все равно можете использовать первое решение Donal, если у вас также есть расширение TclX (или его можно установить), но вместо команды [tclX pipe] (http://wiki.tcl.tk/2033) для 'chan pipe ', который встроен в Tcl 8.6. –

+0

@ AxT_8041 Проверьте мою расширенную версию ответа. Это должно покрыть все, что вам нужно. –