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.
#ctrl-alt-delor:~$
#↳ 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
#ctrl-alt-delor:~$
#↳ 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
.
#ctrl-alt-delor:~$
#↳ 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.
/dev/tty
, see this question. – Stephen Kitt Jun 30 '18 at 21:03