Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect non-empty STDIN in Clojure

Tags:

stdin

clojure

How do you detect non-empty standard input (*in*) without reading from it in a non-blocking way in Clojure?

At first, I thought calling using the java.io.Reader#ready() method would do, but (.ready *in*) returns false even when standard input is provided.

like image 633
Jindřich Mynarz Avatar asked Sep 12 '25 05:09

Jindřich Mynarz


1 Answers

Is this what you are looking for? InputStream .available

(defn -main [& args]
  (if (> (.available System/in) 0)
    (println "STDIN: " (slurp *in*))
    (println "No Input")))

$ echo "hello" | lein run
STDIN:  hello

$ lein run
No Input

Update: It does seem that .available is a race condition checking STDIN. n alternative is to have a fixed timeout for STDIN to become available otherwise assume no data is coming from STDIN

Here is an example of using core.async to attempt to read the first byte from STDIN and append it to the rest of the STDIN or timeout.

(ns stdin.core
  (:require
   [clojure.core.async :as async :refer [go >! timeout chan alt!!]])
  (:gen-class))

(defn -main [& args]
  (let [c (chan)]
    (go (>! c (.read *in*)))
    (if-let [ch (alt!! (timeout 500) nil
                       c ([ch] (if-not (< ch 0) ch)))]
      (do
        (.unread *in* ch)
        (println (slurp *in*)))

      (println "No STDIN")))) 
like image 131
Scott Avatar answered Sep 13 '25 19:09

Scott