Welcome! Please see the About page for a little more info on how this works.

0 votes
ago in Clojure by

I'm sure this is embarrassingly simple, but I can't seem to figure out how to pipe stdout to stdin with clojure.java.process.

With clojure.java.shell, I could do something like

(sh "cat" "-" :in (:out (sh "echo" "hi")))

I realize this is an indirect way to handle this since it's blocking and is handling everything as strings instead of native Java objects.

With clojure.java.process, I could do something like

(exec "bash" "-c" "echo hi | cat -")

but that's just using Bash.

I know there are other, third-party libraries such as Babashka/process and Raynes/conch, but I'd like to learn how to do this with the new Clojure library.

My instinct was to try

(exec {:in (stdout (start "echo" "hi"))} "cat" "-")

or something to that effect, but it doesn't work.

1 Answer

0 votes
ago by

If you want to run one process then I would do the bash example. If you want to create two procs and pipe between them you can do that with the ProcessBuilder.Redirect.PIPEs - there will be two calls to start, just like you had two calls to sh.

ago by
I don't have an example handy atm but maybe there is more plumbing there than I think there is. I know they added explicit PipelineBuilder support in Java 9 (we were staying at Java 8 compatibility so couldn't expose that), so there might be an opportunity there to smooth this over in Clojure 1.13 (which will depend on Java 17).
ago by
Okay. Thanks.

I was looking at the Clojure docs, and there doesn't appear to be a function for this, but I'm guessing I could try it with Java interop? I'm using Java 21, so it should be in there.

    (import 'java.lang.ProcessBuilder$Redirect)

I read your Programming Clojure book, but I'm still very new to a lot of the language. I'm not sure what to do with it after importing.

I'm guessing Clojure 1.13 is a few years away.
ago by
edited ago by
Just messing around, I found something that I think looks reasonable, but I'm not sure if it's blocking or has other performance issues.

  (let [c (start "cat" "-")
        e (start "echo" "hi")]
    (with-open [w (io/writer (stdin c))
                r (io/reader (stdout e))]
      (io/copy r w))
    (println (slurp (stdout c))))

edit: That appears to work for the single example of `echo hi | cat -`, but not the more complicated one I am actually interested in.
...