Reading STDIN always buffered?

Hi there! I am trying to read data from stdin, and am havig some trouble when there is less than a line of data. Here’s some sample code:

m = IO::Memory.new
STDIN.read_buffering=false
m << STDIN.gets_to_end
pp! m.to_s

If I run it and type “1234<Ctrl+D>” this should print 1234, but doesn’t, it just keeps waiting for more input.

Unless I send Ctrl+D right after a newline, it always keeps waiting for data, so

1234\n<Ctrl+D> works
1234\n5678<Ctrl+D> doesn’t

Any ideas?

Update: This works, which is more confusing to me :smiley:

echo -n "hola" | crystal run stdin.cr
m.to_s # => "hola"

UPDATE
found some code in stack overflow that solves the whole thing (even shows how to do “echo * for passwords” if desired

# Fix for crystal bug
STDIN.blocking = true

# STDIN chars without buffering
STDIN.raw do
  # Dont echo out to the terminal
  STDIN.noecho do
    final_password = ""
    while char = STDIN.read_char
      # If we have a backspace
      if char == '\u{7f}'
        # Move the cursor back 1 char
        if final_password != ""
          STDOUT << "\b \b"
          STDOUT.flush
          final_password = final_password[0...-1]
        end
        next
      elsif char == '\u{3}'
        # Control + C was pressed. Get outta here
        Process.exit 0
      elsif char == '\u{4}'
        # Control + D was pressed. Finished
        break
      elsif char.ascii_control?
        # A Control + [] char was pressed. Not valid for a password
        next
      end

      STDOUT << "*"
      STDOUT.flush
      final_password += char
    end

    puts final_password
  end
end

On unix like sysems ctrl D or ^D triggers end of file as below:

  1. CTRL D is pressed on an empty line
  2. CTRL D is pressed twice on a non-empty line

So in your case, you need to press ^D twice for the shell to trigger end of file signal.

HIH

4 Likes

Indeed that works, but it’s not how other unix tools work like, for example cat ends immediately on the first Ctrl+d

I guess it may be because it’s not just reading stdin but using it as a tty or something.

Anyway, good enough, thanks!

On my machine, I have to hit it twice if it’s not at the beginning of a line.