There's a general buffering rule followed by the C standard I/O library (
stdio) that most unix programs use. If output is going to a terminal, it is flushed at the end of each line; otherwise it is flushed only when the buffer (8K on my Linux/amd64 system; could be different on yours) is full.
If all your utilities were following the general rule, you would see output delayed in all of your examples (
cat|tr|sed). But there's an exception: GNU
cat never buffers its output. It either doesn't use
stdio or it changes the default
stdio buffering policy.
I can be fairly sure you're using GNU
cat and not some other unix
cat because the others wouldn't behave this way. Traditional unix
cat has a
-u option to request unbuffered output. GNU
cat ignores the
-u option because its output is always unbuffered.
So whenever you have a pipe with a
cat on the left, in the GNU system, the passage of data through the pipe will not be delayed. The
cat isn't even going line by line - your terminal is doing that. While you're typing input for cat, your terminal is in "canonical" mode - line-based, with editing keys like backspace and ctrl-U offering you the chance to edit the line you have typed before sending it with Enter.
tr is still receiving data from
cat as soon as you press Enter, but
tr is following the
stdio default policy: its output is going to a pipe, so it doesn't flush after each line. It writes to the second pipe when the buffer is full, or when an EOF is received, whichever comes first.
sed is also following the
stdio default policy, but its output is going to a terminal so it will write each line as soon as it has finished with it. This has an effect on how much you must type before something shows up on the other end of the pipeline - if
sed was block-buffering its output, you'd have to type twice as much (to fill
tr's output buffer and
sed's output buffer).
-u option so if you reversed the order and used
cat|sed -u|tr you would see the output appear instantly again. (The
sed -u option might be available elsewhere but I don't think it's an ancient unix tradition like
cat -u) As far as I can tell there's no equivalent option for
There is a utility called
stdbuf which lets you alter the buffering mode of any command that uses the
stdio defaults. It's a bit fragile since it uses
LD_PRELOAD to accomplish something the C library wasn't designed to support, but in this case it seems to work:
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'