Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restart stdin after Ctrl+D?

Tags:

c

linux

Running a program expecting input from terminal I can ”close” stdin by Ctrl+D. Is there any way to reopen stdin after that?

like image 206
Andreas Avatar asked Jul 05 '18 15:07

Andreas


1 Answers

In linux and on POSIXy systems in general, the standard input descriptor is not closed when you press Ctrl+D in the terminal; it just causes the pseudoterminal layer to become readable, with read() returning 0. This is how POSIXy systems indicate end of input.

It does not mean the file descriptor (or even the stream handle provided on top of it by the C library) gets closed. As Steve Summit mentioned in a comment, you only need to clear the end-of-input status of the stream using clearerr(), to be able to read further data; this tells the C library that you noticed the status change, but want to try further reading anyway.

A similar situation can occur when a process is writing to a file, and another reads it. When the reader gets to the end of the file, a read() returns 0, which the C library understands as end-of-input; it sets an internal flag, so that unless you call clearerr(), feof() will return true for that stream. Now, if the writer writes more data, and the reader does a clearerr(), the reader can read the newly written additional data.

This is perfectly normal, and expected behaviour.

In summary:

  • End of input is indicated by a read() operation returning 0, but the file descriptor status does not change, and can be used as normal.

  • Ctrl+D on a terminal causes only that to happen; the file descriptors open to the terminal are not affected in any other way, and it is up to the foreground process reading the terminal input to decide what it does. It is allowed to simply go on reading more data.

    Most programs do exit when that happens, but that is a convention, not a technical requirement at all.

  • The C library detects read() returning 0, and sets its internal "end of input seen" flag for that stream. That causes feof() to return true, fgets() to return NULL, fgetc() to return EOF, and so on, for that stream.

  • Calling clearerr() on the stream handle clears the flag, so that the next read attempt will actually try to read further data from the descriptor.

    This is described in the very first sentence in the Description section of the man 3 clearerr man page.

like image 91
Nominal Animal Avatar answered Oct 25 '22 01:10

Nominal Animal