2013-04-26 2 views
1

Хотя я хорошо знаком с Tcl, это вопрос начинающего. Я хотел бы читать и писать из трубы. Я хотел бы решение в чистом Tcl и не использовать библиотеку вроде Expect. Я скопировал пример из wiki tcl, но не смог запустить его.Простая программа, которая читает и записывает в трубу

Мой код:

cd /tmp 
catch { 
    console show 
    update 
} 

proc go {} { 
    puts "executing go" 

    set pipe [open "|cat" RDWR] 
    fconfigure $pipe -buffering line -blocking 0 
    fileevent $pipe readable [list piperead $pipe] 

    if {![eof $pipe]} { 
     puts $pipe "hello cat program!" 
     flush $pipe 
     set got [gets $pipe] 
     puts "result: $got" 

    } 
} 

go 

Выход executing go\n result:, однако я бы ожидать, что при чтении значения из трубы будет возвращать строки, которые я послал в программе кошачьих.

Какая у меня ошибка?

-
EDIT:

Я последовал ответ potrzebie и получил небольшой пример работает. Этого достаточно, чтобы заставить меня идти. Быстрое обходное решение для тестирования моей установки - это следующий код (не настоящее решение, а быстрое решение на данный момент).

cd /home/stephan/tmp 
catch { 
    console show 
    update 
} 

puts "starting pipe" 
set pipe [open "|cat" RDWR] 
fconfigure $pipe -buffering line -blocking 0 
after 10 
puts $pipe "hello cat!" 
flush $pipe 

set got [gets $pipe] 
puts "got from pipe: $got" 
+0

Я упомянул «после» только для демонстрации, извините, если это было непонятно.Это нехорошее решение, потому что он всегда ждет фиксированного количества времени, и вы хотите, чтобы скрипт немедленно ответил, когда есть строка для чтения. Если вы используете 'after' в любом случае (это проще, чем настройка обработчика' fileevent'), вы должны сделать это * повторно * до тех пор, пока не получите строку с 'gets'. – potrzebie

+0

Было ясно. Мне просто нужен был быстрый пример, который работает сейчас, я всегда могу улучшить код. Я тоже попробовал fileevent, но, вероятно, имел ошибку в моем коде. Также я хочу, чтобы код tcl вызывал мою собственную программу, написанную на другом языке. Еще раз спасибо за ваш ответ. – mrsteve

ответ

2

Запись на трубу и промывку не заставит многозадачность OS немедленно покинуть вашу программу и переключиться на программу cat. Попробуйте поставить after 1000 между puts и командой gets, и вы увидите, что вы, вероятно, вернете строку. cat был предоставлен некоторый отрезок времени и имел возможность прочитать его ввод и написать его вывод.

Вы не можете контролировать когдаcat читает ввод и записывает его обратно, так что вам придется использовать либо fileevent и войти в цикл обработки событий ждать (или периодически вызывать update), или периодически пытаться чтение из поток. Или вы можете сохранить его в режиме блокировки, и в этом случае gets будет ждать вас. Он будет блокироваться до тех пор, пока не будет прочитана строка, но пока не будет отправлено других событий. Например, GUI перестает отвечать.

Пример представляется для Tk и предназначен для запуска wish, который автоматически вводится в цикл событий в конце скрипта. Добавьте процедуру piperead и запустите сценарий с wish или добавьте команду vwait в конец скрипта и запустите ее с помощью tclsh.

PS: Для ввода-вывода с линейной буферизацией для работы в трубе обе задействованные программы должны использовать ее (или без буферизации). Многие программы (grep, sed и т. Д.) Используют полную буферизацию, когда они не подключены к терминалу. Один из способов предотвратить их - это программа unbuffer, которая является частью Expect (вам не нужно писать сценарий Expect, это отдельная программа, которая просто входит в пакет Expect).

set pipe [open "|[list unbuffer grep .]" {RDWR}] 
+0

В некоторых версиях 'cat' есть опция' -u' для отключения буферизации вывода. Не помогает ни для какой другой программы. –

1

Я предполагаю, что вы выполняете код из http://wiki.tcl.tk/3846, страницы под названием «Труба против Ожидайте». Вы, кажется, пропустили определение процесса piperead, действительно, когда я копировал и вставлял код из вашего вопроса, у меня была ошибка invalid command name "piperead". Если вы копируете и вставляете определение из вики, вы должны обнаружить, что код работает. Это, безусловно, для меня.

Смежные вопросы