Is there a difference between unbuffer(1) and stdbuf(1)? From what I gather, unbuffer makes more than the "best effort" of calling the libc function set(X)buf at the beginning, and then letting things be?
They work in completely different ways.
The program unbuffer uses expect to run the named command. Because expect creates a pseudo-tty to attach to the stdout of the child process, the child might be fooled into thinking that it should use line-buffering instead of block-buffering. Some programs will change their behaviour when isatty(stdout) is true, others won't and it is very hard to know which will and which won't.
The program stdbuf attempts to put libstdbuf in front of libc for dynamically loaded binaries. Where libstdbuf redefines the default buffering strategy of the libc stdio calls.
I found this out by
apt-get source expect coreutils
and reading the relevant source for each program.
The older, accepted answer is still correct. The main difference in my own experience is that unbuffer is simpler to use and provides only one switch (
-p) for use in pipelines to buffer standard input, which unbuf will not do.
While specific use cases may vary, I'd offer the follow general advice:
- Use unbuffered if you need to buffer standard input and understand the limitations of buffering standard input, i.e. hanging if the pipeline exits early or early termination on EOF.
- Use stdbuf when you need separate control over the buffering for input, output, and error I/O streams, and if you don't need to buffer standard input.
Stdbuf from Coreutils
- Commands like tee that adjust buffers themselves will be unaffected.
- Filters that don't use I/O streams aren't affected.
- Line buffering is invalid with standard input.
So, in general, stdbuf gives you more control than unbuffer, but there are a number of caveats.
man 1 stdbuf (or
man 1 gstdbuf on some systems) says:
NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for example) then that will override corresponding changes by 'stdbuf'. Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O, and are thus unaffected by 'stdbuf' settings...
On GLIBC platforms, specifying a buffer size, i.e., using fully buffered mode will result in undefined operation.
Unbuffered from Expect
The unbuffered command, which is one of the standard expect command line example tools, offers fewer knobs to twiddle. This may or may not be a benefit for you. Personally, I prefer simplicity unless I need the additional knobs. On the other hand, while stdbuf won't work with standard input, unbuffered can when using the
Normally, unbuffer does not read from stdin. This simplifies use of unbuffer in some situations. To use unbuffer in a pipeline, use the -p flag.
However, this behavior comes with a caveat and some further explanation about why if you read
man 1 unbuffered:
unbuffer -p may appear to work incorrectly if a process feeding input to unbuffer exits. Consider:
process1 | unbuffer -p process2 | process3
If process1 exits, process2 may not yet have finished. It is impossible for unbuffer to know long to wait for process2 and process2 may not ever finish, for example, if it is a filter. For expediency, unbuffer simply exits when it encounters an EOF from either its input or process2.
In such cases, unbuffered recommends hand-tuning the pipeline, using Expect directly, or various other workarounds instead.