Search code examples
cterminalstdineofgetchar

Why does the Linux(?)-Terminal not "consume" '\n' EOF?


From what I've read, the Linux terminal (in default settings) buffers the input and only sends it after receiving either EOF or '\n'.

When I loop c = getchar(); and check each c for being EOF (end then break) I need to do CTRL-D twice in order to stop reading, as the first EOF is always consumed by the terminal (I know one can change the terminal to raw, but maybe this is a bit overkill).

However, when I check for c being '\n' (which also sends the input) it will not be consumed.

Example:

  • Input: "abc\n"
    • Characters read: 'a','b','c','\n'
  • Input: "abc" and Ctrl-D
    • Characters read: 'a','b','c'
  • Input: "abc", Ctrl-D and Ctrl-D again
    • Characters read: 'a','b','c',EOF
  • Input: "abc", Return and Ctrl-D
    • Characters read: 'a','b','c','\n',EOF

Isn't this highly inconsistent? Or is there any rationale behind it?

I want to parse input including whitespaces and thus cannot check for '\n' but for EOF - is that possible without changing the terminal to raw?

I've tried with feof(stdin) too, but apperently this doesn't work either :/


Solution

  • That's not how it works. ^D sends on the currently buffered line, so if you don't hit it immediately after a newline, your program will not see an empty read and will not know the input is ended. So you need another ^D to send nothing. But your program never sees a ^D.

    In fact you can use stty to change the terminal's EOF character, so that for example ^N will end the input; your program will run exactly the same, because it does not depend of the value of the EOF keyboard character.

    PS. Since you were trying to write a C program: the input calls return EOF when they try to read a file, and get an empty buffer (0 characters). In fact, EOF is not ^D as you imagine, but -1: This value was chosen because it does not fit in a byte, while read() could legally return any possible byte (yes, even '\04' aka ^D). This is why the signature of getchar() says it returns an int.