How to do binary-safe "exec":
proc bexec {command input} { # Execute shell "command", send "input" to stdin, return stdout. # Ignores stderr (but "2>@1" can be part of "command"). # Supports binary input and output. e.g.: # set flac_data [bexec {flac -} $wav_data] # Run "command" in background... set f [open |$command {RDWR BINARY}] fconfigure $f -blocking 0 # Connect read function to collect "command" output... set ::bexec_done.$f 0 set ::bexec_output.$f {} fileevent $f readable [list bexec_read $f] # Send "input" to command... puts -nonewline $f $input close $f write # Wait for read function to signal "done"... vwait ::bexec_done.$f # Retrieve output... set result [set ::bexec_output.$f] unset ::bexec_output.$f unset ::bexec_done.$f fconfigure $f -blocking 1 try { close $f } trap {CHILDSTATUS} {options info} { dict set info -errorinfo $result return -options $info $result } return $result } proc bexec_read {f} { # Accumulate output in ::bexec_output.$f. append ::bexec_output.$f [read $f] if {[eof $f]} { fileevent $f readable {} set ::bexec_done.$f 1 } }
PYK 2014-05-11: The code above does not need to go to the effort of setting the channel to non-blocking , as Tcl will manage the buffer behind the scenes . Forget about setting the channel to non-blocking , dispense with the vwait , send the desired data into the channel , close the write side of the channel , and then read the output . For code that does need to use non-blocking channels , it's generally best not to interfere with the event loop by using vwait as the code above does . Instead , consider structuring the code such that it works in an event-oriented manner . See also Example of reading and writing to a piped command , which provides a template for conducting an interactive conversation with another process .