I tried to run the following command:

cat | less

I know both commands require something from the standard input. When I run it that's what I expected: all my inputs goes to cat and I will not be able to send commands to less (eventually without being able to quit the program with the command q.).

This is not what happens. Actually, it works properly as long as the number of lines sent in the standard input is less than the number of lines of the screen. When the number of lines sent in the standard input became greather than the number of lines of my consolle, a strange beahviour appeaers. It seems that input is sent sometimes to cat, sometimes to less. For instance, inespectately, the letter q sometims let the program quit.

Why the reason of this behaviour that I (naively) wouldn't expect?

  • another interesting thing is if I do echo a|less it says 'end' at the end, but not with cat|less even when it hits less, With cat|less, when it hit less it shows a colon for a prompt. Which yeah I guess means there's more on the screen. as you say. I guess davidgo's answer about buffering might explain that. BTW I notice just typing less<ENTER> it doesn't prompt for stdin, so it's interesting that you can echo/pipe to it. – barlop Sep 6 '15 at 21:49
  • @barlop nice comment, I guess it's related to another question I have, why less afilename will accept commands in the standard input, and cat afilenime|less will do it too (isn't the standard input of less actually the standardout of cat?). – user1833218 Sep 6 '15 at 21:58
  • less only accepts stdin after it has been given stdin. So for example, type cat<ENTER> you see it is trying to read input. But less is more strange. Try less<ENTER> and it doesn't read input. Give less some input e.g. a file, and then , it wants input. I'm not quite sure what's happening with less.. i'm wondering how it'd be coded, if I knew then i'd get it.. Have you seen code that accepts standard input when it runs?you'd see it enables you to pipe to it and if you don't pipe to it then it prompts you.. i'm not sure though also about specifying a filename.. how it atkes that over stdin – barlop Sep 6 '15 at 22:16

CAT will accept input from stdin (although arguably it more sensibly prefers input from a file or pipe), AND OUTPUTS IT TO STDOUT

This means that the input is simply piped through cat, and then directed on to less. Thus you can see the output in less.

Your confusions are most likely coming in with buffering. CAT is buffering the input and will be batching it (or waiting for end of file) when sending it on to less for formatting.


I hate myself for saying this, but

There’s more than one way to skin a cat.

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 afilename

which means 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 tty command.  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 ttyname(1) 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 (cat and less) 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 less.
  • At some point, less calls ttyname(1), 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).
  • Then, 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 (cat and less) reading from the terminal simultaneously, and the pinball phenomenon kicks in — the characters (and/or lines) that you type go to either cat or less, semi-randomly.  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 less command.

This doesn’t really have anything to do with buffering.

  • 1
    Good answer, but less just opens /dev/tty: "/dev/tty: In each process, a synonym for the controlling terminal associated with the process group of that process, if any. It is useful for programs or shell procedures that wish to be sure of writing messages to or reading data from the terminal no matter how output has been redirected. It can also be used for applications that demand the name of a file for output, when typed output is desired and it is tiresome to find out what terminal is currently in use." (Posix: pubs.opengroup.org/onlinepubs/9699919799/basedefs/…) – rici Sep 8 '15 at 15:20
  • D'oh!  You're right; I overlooked the obvious. – Scott Sep 8 '15 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.