I'm adding hooks support to #eca, which allows user to spawn commands after something happens, tool call etc. I'm struggling a little bit with passing stdin to the command if spawn it from a bash command ๐งต
@(p/process {:continue true
:in "{\"foo\": \"bar\"}"
:out :string
:err :string}
"bash -c" "echo $1")
I know the :in goes to the bash command which is not what we want, any suggestions how to make it goes to the echo one
I'm missing something because even without bash -c it prints $1\n , like it's escpaing the arg
this seems to be almost there:
(p/sh {:continue true
:in "{\"foo\": \"bar\"}"}
"bash" "-c" "echo $1")well, I asked eca and it worked ๐
;; Send input via STDIN using :in.
;; Note: in bash, $1 is a positional argument; it does NOT read STDIN.
;; To read STDIN, use `read` (single line) or a loop.
(p/sh {:continue true
:in "{\"foo\": \"bar\"}\n"}
"bash" "-c" "read -r x; echo \"$x\"")
;; If you specifically want to use $1, pass the value as an argument (not via :in):
(p/sh {:continue true}
"bash" "-c" "echo \"$1\"" "--" "{\"foo\": \"bar\"}")
probably will go with the latter\it's working great so far, thanks duckie
Hi, as an exercise I've tryed to rewrite a bash-onliner to babashka so <file.gz gunzip | tee >(sha1sum > file.sha1) | xz > file.xz was transformed to
(require '[babashka.process :refer [pipeline pb process]])
(require '[ :as io])
(let [in-sha1sum (-> (process {:out "file.sha1"} "sha1sum")
:in
io/writer)]
(pipeline
(pb {:in (io/file "file.gz")}
"gunzip")
(pb "tee" in-sha1sum)
(pb {:out "file.xz"}
"xz"))
(.close in-sha1sum))
A bit longer, but that's ok. The problem I've got: it creates a file named like .BufferedWriter@6c3da8ae with uncompressed content of file.gz. And I actually don't understand why. Could you please explain it for me?The problem is this:
(pb "tee" in-sha1sum)
Here you feed a writer object as an argument to teeso maybe it should be this:
(with-open [in-sha1sum (-> (process {:out "file.sha1"} "sha1sum")
:in io/writer)]
(pipeline
(pb {:in (io/file "file.gz")}
"gunzip")
(pb {:err in-sha1sum} "tee")
(pb {:out "file.xz"}
"xz")))nice trick, thanks, let me think about that
I'd recommend adding run! check so you don't close the writer before the process has ended.
(with-open [in-sha1sum (-> (process {:out "file.sha1"} "sha1sum")
:in io/writer)]
(run! check
(pipeline
(pb {:in (io/file "file.gz")}
"gunzip")
(pb {:err in-sha1sum} "tee")
(pb {:out "file.xz"}
"xz"))))the trick is that tee writes both to stderr and stdout, right?
If I understand it correct โ yes. For now it just an excercise how to force a program to use another program's input instead of a file
But that's different: it connects stdout of echo to stdin of cat. While process substitution allows to substitute stdin of a process2 so process1 will think it's a file.
to make process1 think it's a file, use io/file explicitly
oh I see what you mean, yeah that doesn't work here unless you write to a temporary file yourself
which you can do with (fs/file (fs/temp-dir) "1") or so
nice, thanks. I'll try it.
I don't think this is going to work out here though
in the bash example, unless you block the tee call to wait for it to finish writing the tmp file
I'm a bit lost. How the check works this case it dereferences the last or all processes in a pipeline?
Thanks for youy help, it's less mystical for me now. I'll continue to work on it tomorrow.
how check works in this case: in which case?
check should wait a process'es finish isn't it? So, we have proc1 โ tee ./file โ proc2. Let's assume tee writes into the ./file slowly than proc2 consumes it's input. So proc2 already finished, but tee still not.
proc2 won't finish until it consumes all input
So, does proc2 finished means all the pipeline finished.
yes
proc2 can consumes input faster than tee writes a data into a disk. That's my concern. But I think I'll do an experiment and test it tomorrow.
Again, thanks for your help.
that might be an issue. you could just wait for tee to finish before kicking off sha1sum on the tmpfile
but how it works with stderr is also fine I guess