Both cat
and strings
, and most similar utilities¹, read a little bit of input at a time, process it, then read more input, and so on. So in your case, cat
only reads what less
displays, plus a little more that's in transit.
In more detail, the basic operation of cat
is:
- Reserve a few kilobytes of memory for use as a buffer.
- While there's more input available:
- Read up to N bytes of input into the buffer. (This overwrites data that was written out in a previous cycle.)
- Write the buffer content to the output.
The write operation blocks until there's a place to copy the output. When the output of a pipe, the pipe itself consumes a little memory in the kernel, which is called the pipe buffer. Once that's full, if cat
tries to write to the pipe, the write attempt blocks until there's room. There can be room in the pipe buffer when the process on the read end of the pipe reads some data.
The strings
program works in the same way as cat
, except that it doesn't copy its whole input, only selected parts.
The less
program works a bit differently: it keeps everything that it's read in memory. It doesn't recycle its buffer, it keeps growing it as long as more input keeps coming in. The read part is similar, however, in that less
only reads data when it needs it: it only reads up to the last line that it displays, plus a little more that it reads in anticipation if available.
So when you run sudo cat /dev/sda | strings | less
, what's been read from /dev/sda
consists of:
- Data that
less
has already displayed (or scrolled past).
- Up to a few kB of data that
less
has read but not yet displayed.
- Up to a few kB in the pipe buffer between
strings
and less
.
- Up to a few kB in the memory of
strings
.
- Up to a few kB in the pipe buffer between
cat
and strings
.
- Up to a few kB in the memory of
cat
.
You can watch when each program reads and writes data by tracing its system calls:
sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less
and watch the *.strace
files. You can also check how much cat
has read by checking the file offset, for example with lsof -p1234
or with head /proc/1234/fdinfo/0
where 1234
is the process ID of cat
.
¹ Among the basic text processing utility, the main exception is sort
, which can't emit any output until it's read the whole input: for all it knows, the first line of output may well be the last line of input that it reaches.
yes hallo baby | less
does not first load the infinite output ofyes
before piping it toless
. This strange notion of commands in a pipeline being run sequentially certainly has its origin in some lousy textbook or tutorial, I don't think that so many people fell in the same trap by themselves.