According to this answer by schily, less reads navigation commands from stderr if it's not able to open /dev/tty.

This seems puzzling, since I've never seen anything write to another program's stderr stream, and I don't know how I would even accomplish that.

What is the purpose of stderr being open for both reading and writing? And if this is useful, how do I make use of it on modern systems? (Is there some arcane syntax to pipe something into stderr instead of stdin, for instance?)

2 Answers 2


I was surprised at first. However after reading the answers, and doing a little investigation, it seems simple. So here is what I have found. (in the end there was no surprise.)

Before redirection stdin, stdout, and stderr are as expected connected to the same device.

#↳ ll /dev/std*
lrwxrwxrwx 1 root root 15 Jun  3 20:58 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Jun  3 20:58 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Jun  3 20:58 /dev/stdout -> /proc/self/fd/1

#↳ ll /proc/self/fd/*
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/0 -> /dev/pts/12
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/1 -> /dev/pts/12
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/2 -> /dev/pts/12

Therefore after most re-directions (that is if stderr) is not redirected. stderr is still connected to the terminal. Therefore it can be read, to get keyboard input.

The only thing that is stopping the files being used in the unexpected direction is convention, and the pipes are unidirectional.

Another example, try:

cat | less

This goes wrong after a page, when less tries to read the terminal (this is not a surprise, as cat is also reading the terminal).

/dev/tty is more mysterious, it is not a link into /proc/self.

#↳ ll /dev/tty
crw-rw-rw- 1 root tty 5, 0 Jun 29 09:18 /dev/tty

See what relations are between my current controlling terminal and `/dev/tty`? for an explenation. Thanks to @StephenKitt for the link.


When you log in, stdin, stdout and stderr are connected to the terminal from where you log in. To be more exact, the tty is typcally opened and stdout and stderr are a result from two dup(2) operations on the first file descriptor. This allows to read from stderr in order to get input from the termnal.

As mentioned in the other answer, programs read from stderr in order to get an interactive reply on a question.

Since a user cannot know under which circumstances a program reads from stderr, it is a useless attempt to intentionally write data into stderr from another program.

Note that today programs usually first try to open /dev/tty and use stderr only in case that does not work.

Programs that only read from stderr usually have never been modified since before 1979 and such programs usualy contain constructs like:

int i 1;


i =* 2;

that are not accepted by modern C compilers. As a result, it is most unlikely that you today will find a program that never opens /dev/tty but rather reads interactive replies from stderr.

  • So if I'm understanding right, the shell connects stderr to the tty when stdin is redirected (via pipe or other means)? Or just always connects stderr to the tty?
    – Draconis
    Jun 30, 2018 at 17:47
  • 1
    When you log in, stderr is connected to your login terminal.
    – schily
    Jun 30, 2018 at 18:00
  • 2
    i =+ 1 is perfectly valid C, and is equal to i = (+1). Granted, the former is nice candidate for the underhanded C contest.
    – G. Sliepen
    Jun 30, 2018 at 18:57
  • 1
    OK, it may be that it just creates a warning. I changed the code to something else from C in 1977.
    – schily
    Jun 30, 2018 at 19:14
  • 1
    It seems that I am aware of more shells, since I do know of at least one shell that reads from other than its standard input. (-:
    – JdeBP
    Jul 1, 2018 at 0:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .