Pergunta

I'm trying to connect with a server using plink, execute a command and 'pipe' output into my text widget:

set myCommand "echo command | plink.exe -ssh server -pw lucas" 
catch {eval exec cmd.exe $myCommand } res
.text insert end $res
# remote command is not working that's why I'm sending command using echo and I'm executing it in cmd.exe because tcl not recognize echo command

Unfortunatelly catch is not working here. Command is executed in the background and nothing happens. No piping into my text widget. It would be great if catched output would be transmited in real time.

That's why I've tried this:

http://wiki.tcl.tk/3543

package require Tk
set shell cmd.exe
proc log {text {tags {}}} {
    .output configure -state normal
    .output insert end $text $tags
    .output configure -state disabled
    .output see end
}
proc transmit {} {
    global chan
    log "\$ [.input get]\n" input
    puts $chan [.input get]
    .input delete 0 end
}
proc receive {} {
    global chan
    log [read $chan]
}
entry .input
scrollbar .scroll -orient vertical -command {.output yview}
text .output -state disabled -yscrollcommand {.scroll set}
.output tag configure input -background gray
pack .input -fill x -side bottom
pack .scroll -fill y -side right
pack .output -fill both -expand 1
focus .input
set chan [open |$shell a+]
fconfigure $chan -buffering line -blocking 0
fileevent $chan readable receive
bind .input <Return> transmit

and it's working under cygwin, but after wrapped to .exe when I'm trying execute a command, plink is opening me new black cmd window (why???) where the command is executing and output appears. From this wndow I cannot anymore pipe the output.

Foi útil?

Solução

Many issues here. Hopefully these notes will help you figure out what to do.


It seems a bit over-complicated to run things through cmd.exe just to make echo piped into plink.exe work. I'd write that like this:

catch { exec plink.exe -ssh server -pw lucas << "command" } res

Note that like this, we don't need to use eval at all.


Failing that, if that command is something coming from the user and you need to support command shell syntax with it, you can do this:

set myCommand "echo command | plink.exe -ssh server -pw lucas" 
catch { exec cmd.exe /C $myCommand } res

Otherwise you get into the mess of stuff related to the parsing of options to cmd.exe and that's probably not what you want! (That /C is important; it tells cmd.exe “here comes a command”.)

Note that we're still avoiding eval here. That eval is (almost) certainly a bad idea with what you're trying to do.


When working with wrapped code, the problem is a different one. The issue there is that Windows processes each use a particular subsystem (it's effectively a compilation option when building the executable if I remember right) and the wrapped wish.exe and cmd.exe use different subsystems. Going across the subsystem boundaries is very messy, as the OS tries to be helpful and does things like allocating a terminal for you. Which you didn't want. (I don't remember if you have the problem with direct use of plink.exe, and I can't check from here due to being on entirely the wrong platform and not having a convenient VM set up.)


To run the plink.exe in the background, assemble the pipeline like this:

set myCmd [list plink.exe -ssh server -pw lucas]

set chan [open |$myCmd a+];    # r+ or w+ would work just as well for read/write pipe
fconfigure $chan -buffering none -blocking 0

puts $chan "command"

Also, be aware that when using fileevent you need to take care to detect an EOF condition and close the pipe when that happens:

proc receive {} {
    global chan
    log [read $chan]
    if {[eof $chan]} {
        close $chan
    }
}

Otherwise when the pipe is closed you'll get an infinite sequence of events on the pipe channel (and the read will always produce a zero-length result since there's provably nothing there).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top