Re: Struggling in making a sub-process work in an interactive way
I replied a bit too fast, I didn't realized you wanted to such an advanced thing It is probably more a JVM question than a Clojure question then. On Fri, Jan 13, 2012 at 3:42 AM, jaime xiejianm...@gmail.com wrote: Well actually I also tried commons-exec but it's the same as clojure.java.shell - they run system command directly, after execution they return and terminate. That's not the way I want On Jan 13, 2:42 am, Denis Labaye denis.lab...@gmail.com wrote: Hi, In Java you would do it with common-exec:http://commons.apache.org/exec/ So add the deps to your project.clj : :dependencies [[org.apache.commons/commons-exec 1.1]] And use Clojure's Java interop. Keep us posted, I will need to do the same thing soon :) Denis On Wed, Jan 11, 2012 at 4:05 AM, jaime xiejianm...@gmail.com wrote: I didn't read your code carefully yet but I think you're meaning to copy streams between my Clojure code and the sub-process, actually I've tried this but this is probably not what I want. I might not make myself clear. So here I go again: 1. I writing a program which will open an OS shell (that means cmd under Windows and bash under Linux) as sub-process 2. this shell thing will not terminate while my code is still running, all system commands such as dir/ls/cat etc. will be thrown into the shell's input-stream to execute and the result is pulled from shell's output-stream/err-stream 3. because when the shell will finish its execution is unpredictable, I chained an echo stop-sign command to original command so that the program can get the sign when execution done. E.g. for command dir, I will throw dir echo stop-sign to the shell, when a stop-sign is captured then it knows the execution finished 4. it works well so far but when the system command is interactive one such as 'time' (in Windows), the program will hang; if there are ways to know when to require user input then I can resolve this in the code, but the answer is NO. I didn't find a way to detect this 5. thus I tried to find out any workarounds but failed. I also tried the way you mentioned here, it can work in an interactive way but in this case I cannot get the control back. That's all the things I'm struggling on... On Jan 10, 4:54 pm, Alan Malloy a...@malloys.org wrote: On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. I was going to attach a simple proof of concept to this, but I can't seem to get it right. So instead, here's what I was trying to do, and if someone wants to take it up this might be something useful to work from: (ns fork.core (:require [clojure.java.io :as io]) (:import (java.io PipedReader PipedWriter)) (:gen-class)) (defn -main [ args] (println Start typing, I'll cat it back atcha!) (let [child (- (Runtime/getRuntime) (.exec /bin/cat)) cin (.getInputStream child) cout (.getOutputStream child) in-pipe-in (PipedReader.) in-pipe-out (PipedWriter. in-pipe-in) out-pipe-in (PipedReader.) out-pipe-out (PipedWriter. out-pipe-in) in *in*, out *out*] ;; avoid dynamic-binding issues (future (io/copy in in-pipe-out)) ;; read my stdin... (future (io/copy in-pipe-in cout)) ;; write it to child's stdin (future (io/copy cin out-pipe-out)) ;; read child's stdout... @(future (io/copy out-pipe-in out)) ;; write it to my stdout, and wait for it to finish (let [exit-code (.waitFor child)] (println Child process finished with exit code exit-code) exit-code))) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to
Re: Struggling in making a sub-process work in an interactive way
Hi, In Java you would do it with common-exec: http://commons.apache.org/exec/ So add the deps to your project.clj : :dependencies [[org.apache.commons/commons-exec 1.1]] And use Clojure's Java interop. Keep us posted, I will need to do the same thing soon :) Denis On Wed, Jan 11, 2012 at 4:05 AM, jaime xiejianm...@gmail.com wrote: I didn't read your code carefully yet but I think you're meaning to copy streams between my Clojure code and the sub-process, actually I've tried this but this is probably not what I want. I might not make myself clear. So here I go again: 1. I writing a program which will open an OS shell (that means cmd under Windows and bash under Linux) as sub-process 2. this shell thing will not terminate while my code is still running, all system commands such as dir/ls/cat etc. will be thrown into the shell's input-stream to execute and the result is pulled from shell's output-stream/err-stream 3. because when the shell will finish its execution is unpredictable, I chained an echo stop-sign command to original command so that the program can get the sign when execution done. E.g. for command dir, I will throw dir echo stop-sign to the shell, when a stop-sign is captured then it knows the execution finished 4. it works well so far but when the system command is interactive one such as 'time' (in Windows), the program will hang; if there are ways to know when to require user input then I can resolve this in the code, but the answer is NO. I didn't find a way to detect this 5. thus I tried to find out any workarounds but failed. I also tried the way you mentioned here, it can work in an interactive way but in this case I cannot get the control back. That's all the things I'm struggling on... On Jan 10, 4:54 pm, Alan Malloy a...@malloys.org wrote: On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. I was going to attach a simple proof of concept to this, but I can't seem to get it right. So instead, here's what I was trying to do, and if someone wants to take it up this might be something useful to work from: (ns fork.core (:require [clojure.java.io :as io]) (:import (java.io PipedReader PipedWriter)) (:gen-class)) (defn -main [ args] (println Start typing, I'll cat it back atcha!) (let [child (- (Runtime/getRuntime) (.exec /bin/cat)) cin (.getInputStream child) cout (.getOutputStream child) in-pipe-in (PipedReader.) in-pipe-out (PipedWriter. in-pipe-in) out-pipe-in (PipedReader.) out-pipe-out (PipedWriter. out-pipe-in) in *in*, out *out*] ;; avoid dynamic-binding issues (future (io/copy in in-pipe-out)) ;; read my stdin... (future (io/copy in-pipe-in cout)) ;; write it to child's stdin (future (io/copy cin out-pipe-out)) ;; read child's stdout... @(future (io/copy out-pipe-in out)) ;; write it to my stdout, and wait for it to finish (let [exit-code (.waitFor child)] (println Child process finished with exit code exit-code) exit-code))) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Struggling in making a sub-process work in an interactive way
Well actually I also tried commons-exec but it's the same as clojure.java.shell - they run system command directly, after execution they return and terminate. That's not the way I want On Jan 13, 2:42 am, Denis Labaye denis.lab...@gmail.com wrote: Hi, In Java you would do it with common-exec:http://commons.apache.org/exec/ So add the deps to your project.clj : :dependencies [[org.apache.commons/commons-exec 1.1]] And use Clojure's Java interop. Keep us posted, I will need to do the same thing soon :) Denis On Wed, Jan 11, 2012 at 4:05 AM, jaime xiejianm...@gmail.com wrote: I didn't read your code carefully yet but I think you're meaning to copy streams between my Clojure code and the sub-process, actually I've tried this but this is probably not what I want. I might not make myself clear. So here I go again: 1. I writing a program which will open an OS shell (that means cmd under Windows and bash under Linux) as sub-process 2. this shell thing will not terminate while my code is still running, all system commands such as dir/ls/cat etc. will be thrown into the shell's input-stream to execute and the result is pulled from shell's output-stream/err-stream 3. because when the shell will finish its execution is unpredictable, I chained an echo stop-sign command to original command so that the program can get the sign when execution done. E.g. for command dir, I will throw dir echo stop-sign to the shell, when a stop-sign is captured then it knows the execution finished 4. it works well so far but when the system command is interactive one such as 'time' (in Windows), the program will hang; if there are ways to know when to require user input then I can resolve this in the code, but the answer is NO. I didn't find a way to detect this 5. thus I tried to find out any workarounds but failed. I also tried the way you mentioned here, it can work in an interactive way but in this case I cannot get the control back. That's all the things I'm struggling on... On Jan 10, 4:54 pm, Alan Malloy a...@malloys.org wrote: On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. I was going to attach a simple proof of concept to this, but I can't seem to get it right. So instead, here's what I was trying to do, and if someone wants to take it up this might be something useful to work from: (ns fork.core (:require [clojure.java.io :as io]) (:import (java.io PipedReader PipedWriter)) (:gen-class)) (defn -main [ args] (println Start typing, I'll cat it back atcha!) (let [child (- (Runtime/getRuntime) (.exec /bin/cat)) cin (.getInputStream child) cout (.getOutputStream child) in-pipe-in (PipedReader.) in-pipe-out (PipedWriter. in-pipe-in) out-pipe-in (PipedReader.) out-pipe-out (PipedWriter. out-pipe-in) in *in*, out *out*] ;; avoid dynamic-binding issues (future (io/copy in in-pipe-out)) ;; read my stdin... (future (io/copy in-pipe-in cout)) ;; write it to child's stdin (future (io/copy cin out-pipe-out)) ;; read child's stdout... @(future (io/copy out-pipe-in out)) ;; write it to my stdout, and wait for it to finish (let [exit-code (.waitFor child)] (println Child process finished with exit code exit-code) exit-code))) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your
Re: Struggling in making a sub-process work in an interactive way
On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. I was going to attach a simple proof of concept to this, but I can't seem to get it right. So instead, here's what I was trying to do, and if someone wants to take it up this might be something useful to work from: (ns fork.core (:require [clojure.java.io :as io]) (:import (java.io PipedReader PipedWriter)) (:gen-class)) (defn -main [ args] (println Start typing, I'll cat it back atcha!) (let [child (- (Runtime/getRuntime) (.exec /bin/cat)) cin (.getInputStream child) cout (.getOutputStream child) in-pipe-in (PipedReader.) in-pipe-out (PipedWriter. in-pipe-in) out-pipe-in (PipedReader.) out-pipe-out (PipedWriter. out-pipe-in) in *in*, out *out*] ;; avoid dynamic-binding issues (future (io/copy in in-pipe-out)) ;; read my stdin... (future (io/copy in-pipe-in cout)) ;; write it to child's stdin (future (io/copy cin out-pipe-out)) ;; read child's stdout... @(future (io/copy out-pipe-in out)) ;; write it to my stdout, and wait for it to finish (let [exit-code (.waitFor child)] (println Child process finished with exit code exit-code) exit-code))) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Struggling in making a sub-process work in an interactive way
Alan Malloy a...@malloys.org writes: On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. Oops; that's right. What I should have said was that it's a shortcoming of clojure.java.shell. -Phil -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Struggling in making a sub-process work in an interactive way
On Mon, Jan 9, 2012 at 11:20 PM, jaime xiejianm...@gmail.com wrote: now it works fine for NON-interactive command such as dir or help, but it will hang when I send the shell commands that require user input, such as time. I think the reason is that my code doesn't detect any input requirement so the shell keep waiting for an input infinitely. You could get around the blocking I/O problem with java.nio.channels.Selector and the like. Wrapping or duplicating what expect4j does would do the trick. http://code.google.com/p/expect4j/ - Ryan -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Struggling in making a sub-process work in an interactive way
I didn't read your code carefully yet but I think you're meaning to copy streams between my Clojure code and the sub-process, actually I've tried this but this is probably not what I want. I might not make myself clear. So here I go again: 1. I writing a program which will open an OS shell (that means cmd under Windows and bash under Linux) as sub-process 2. this shell thing will not terminate while my code is still running, all system commands such as dir/ls/cat etc. will be thrown into the shell's input-stream to execute and the result is pulled from shell's output-stream/err-stream 3. because when the shell will finish its execution is unpredictable, I chained an echo stop-sign command to original command so that the program can get the sign when execution done. E.g. for command dir, I will throw dir echo stop-sign to the shell, when a stop-sign is captured then it knows the execution finished 4. it works well so far but when the system command is interactive one such as 'time' (in Windows), the program will hang; if there are ways to know when to require user input then I can resolve this in the code, but the answer is NO. I didn't find a way to detect this 5. thus I tried to find out any workarounds but failed. I also tried the way you mentioned here, it can work in an interactive way but in this case I cannot get the control back. That's all the things I'm struggling on... On Jan 10, 4:54 pm, Alan Malloy a...@malloys.org wrote: On Jan 9, 9:24 pm, Phil Hagelberg p...@hagelb.org wrote: jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. This should be possible if you don't mind suiciding your own process's stdin/stdout, by blindly forwarding all your input and output through the child. But if you send the child some input it didn't need, and it terminates, and then later you need your own stdin again, some pieces will be missing. I was going to attach a simple proof of concept to this, but I can't seem to get it right. So instead, here's what I was trying to do, and if someone wants to take it up this might be something useful to work from: (ns fork.core (:require [clojure.java.io :as io]) (:import (java.io PipedReader PipedWriter)) (:gen-class)) (defn -main [ args] (println Start typing, I'll cat it back atcha!) (let [child (- (Runtime/getRuntime) (.exec /bin/cat)) cin (.getInputStream child) cout (.getOutputStream child) in-pipe-in (PipedReader.) in-pipe-out (PipedWriter. in-pipe-in) out-pipe-in (PipedReader.) out-pipe-out (PipedWriter. out-pipe-in) in *in*, out *out*] ;; avoid dynamic-binding issues (future (io/copy in in-pipe-out)) ;; read my stdin... (future (io/copy in-pipe-in cout)) ;; write it to child's stdin (future (io/copy cin out-pipe-out)) ;; read child's stdout... @(future (io/copy out-pipe-in out)) ;; write it to my stdout, and wait for it to finish (let [exit-code (.waitFor child)] (println Child process finished with exit code exit-code) exit-code))) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Struggling in making a sub-process work in an interactive way
Hello there, I'm writing some code, int my code it does following things (under Windows): 1. create a sub-process by (.exec (Runtime/getRuntime) cmd) named shell 2. get input-stream, output-stream and err-stream from the shell object 3. send commands to shell by dropping line into the output-string then get any result from input-stream/err-stream now it works fine for NON-interactive command such as dir or help, but it will hang when I send the shell commands that require user input, such as time. I think the reason is that my code doesn't detect any input requirement so the shell keep waiting for an input infinitely. Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? Thanks, Jaime -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Struggling in making a sub-process work in an interactive way
jaime xiejianm...@gmail.com writes: Later on I tried to add code that can make this possible but I found there's no way to detect if a command requires user's input and thus I have to find another way to make it work - but I didn't success and have been struggling for a workaround for a long while anyone has any idea? As far as I know this is impossible to do without bringing in third-party libraries; this is just a (rather serious) shortcoming of the JDK. I haven't looked into it enough to know which libraries would offer it though. -Phil -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en