I hate myself for saying this, but
There’s more than one way to skin a
By which I mean, there’s standard input, and then there’s standard input.
Or, there’s reading from the keyboard (terminal),
and then there’s reading from the keyboard. Try
less < afilename
It works just like
less must have some way of reading from the keyboard
other than reading from the standard input.
Here’s another command that works, even though you might not expect it to:
less afilename < /dev/null
Look at the
It reports the name of the tty (terminal) connected to the standard input.
It works by calling the
ttyname library function
with an argument of
0 (the file descriptor of the standard input).
less is probably calling
to get the name of the tty (terminal) connected to the standard output.
It then opens that tty for reading, and accepts commands from it.
It does not read commands from the standard input; that’s only for data.
So what we have is two quasi-independent processes (
independently (concurrently) reading from the keyboard
(i.e., the tty / terminal) on two independent file descriptors.
This is a confusing situation, and is something of a “race condition”.
I find it somewhat analogous to the operation of a pinball machine,
in which there are many lanes, or paths, that the ball can take —
and it always takes one; it can never take more than one. Similarly,
when multiple processes are reading from the same terminal simultaneously,
every line that is typed (if the terminal is in line mode)
or every character that is typed (if the terminal is in character mode)
goes to exactly one process.
And the selection is arbitrary, not unlike the action of the pinball.
It’s not fully “random”, any more than the scheduling of processes is random;
but it’s essentially unpredictable.
So, here’s what happens:
cat reads from its standard input, which, by default, is the terminal,
and writes to its standard output, which is the pipe to
- At some point,
gets the name of the terminal it is on, and opens that for reading.
less reads a screen-full of data (i.e., 24 lines, or whatever)
from its standard input (the pipe)
and writes it to the standard output (the terminal).
less issues the
: prompt, puts the terminal into character mode,
and starts reading from the terminal (not from the standard input).
- So, we now have two processes (
reading from the terminal simultaneously,
and the pinball phenomenon kicks in — the characters (and/or lines)
that you type go to either
If it goes to
cat, it gets written to the pipe and
less treats it as data.
If it goes to
less, it is interpreted as a
This doesn’t really have anything to do with buffering.