Non-blocking STDIN read

I doing this:

unless STDIN.tty?
    content = STDIN.gets_to_end
end

when there is no stdin, this works in terminal, but stale when running in docker compose run - because docker not close stdin.

if I do something like this:

unless STDIN.tty?
  STDIN.read_timeout = 0.001.seconds
  content = begin
    STDIN.gets_to_end
  rescue 
    nil
  end
end

it adds timeout of 1sec.

Is there any solution?

On POSIX systems use LibC.select with zero timeout to check if STDIN is readable before reading.

def read_stdin : String?
 fds = LibC::FdSet.new
 fds.fds_bits[0] = 1
 LibC.select(1, pointerof(fds), nil, nil, out tv) > 0 ? STDIN.gets_to_end : nil
end

HIH

Similarly, if the STDIN is opened in nonblocking mode one can just issue `LibC.read` on it until it returns EAGAIN or EOF (and collect the results). Naqvis’ solution seems cleaner.

I do wonder if there are portable solutions though.

It actually was not just docker bug, it was pipeline, ruby with backticks calls docker which run crystal.
when I change backticks to system, bug gone. but still there is some problem in crystal, because no any other soft with stdin capabilities hangs, except crystal.