【问题标题】:Piping a subprocesses output directly to stdout (java/clojure)将子进程输出直接通过管道传输到标准输出(java/clojure)
【发布时间】:2013-01-18 22:59:29
【问题描述】:

我正在寻找一种在 clojure 中启动子进程的方法(java 可以),并将其输出实时直接发送到标准输出。我能找到的最接近的是 clojure 的 Conch 库,它允许您将输出发送到 *out*,但在进程运行完成之前它实际上不会显示输出。

【问题讨论】:

  • 这看起来好像在某处缺少 .flush()。

标签: java clojure exec


【解决方案1】:

不确定是否有一个方便的 Clojure 包装器:

(->> (.. Runtime getRuntime (exec "ls") getInputStream)                                                                                                                   
    java.io.InputStreamReader.                                                                                                                                            
    java.io.BufferedReader.                                                                                                                                               
    line-seq                                                                                                                                                              
    (map println))  

在实践中值得注意的是,你需要同时阅读 stdin 和 stderr 定期进行,否则当其中一个缓冲区填满时,进程可能会挂起。

【讨论】:

    【解决方案2】:

    我将 Arthur 的答案标记为正确,因为它引导我找到了解决方案,而且这基本上是人们在基本情况下想要的。我最终构建了一个更大的方法,它虽然做得更多,但我想我会把它放在这里以防其他人发现它有用

    (defn- print-return-stream     
        [stream]
        (let [stream-seq (->> stream    
                              (java.io.InputStreamReader.)    
                              (java.io.BufferedReader.)       
                              line-seq)]                      
            (doall (reduce
                (fn [acc line]     
                    (println line) 
                    (if (empty? acc) line (str acc "\n" line))) 
                ""                 
                stream-seq))))     
    
    (defn exec-stream              
        "Executes a command in the given dir, streaming stdout and stderr to stdout,
        and once the exec is finished returns a vector of the return code, a string of
        all the stdout output, and a string of all the stderr output"
        [dir command & args]       
        (let [runtime  (Runtime/getRuntime)
              proc     (.exec runtime (into-array (cons command args)) nil (File. dir)) 
              stdout   (.getInputStream proc) 
              stderr   (.getErrorStream proc) 
              outfut   (future (print-return-stream stdout))
              errfut   (future (print-return-stream stderr))
              proc-ret (.waitFor proc)]       
            [proc-ret @outfut @errfut]      
            ))
    

    【讨论】: