Make Piped Commands Respond Promptly with stdbuf
You will finish with a practical way to change the buffering of a command's standard input, output or error stream, which can make a live pipeline show records promptly instead of waiting for a larger buffer. The examples use GNU coreutils 9.4, installed here as Ubuntu package version 9.4-3ubuntu6.3.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell, the coreutils package and a command whose stream buffering you want to adjust. The examples are ordinary user commands. They do not require sudo, and they do not change a service or a configuration file.
1. Check the installed contract
Start by checking the binary and package version. This is read-only:
$ command -v stdbuf
/usr/bin/stdbuf
$ stdbuf --version | head -n 1
stdbuf (GNU coreutils) 9.4
$ dpkg-query -W -f='\${Package} \${Version}\n' coreutils
coreutils 9.4-3ubuntu6.3
Checkpoint: your output should identify GNU stdbuf and the version you intend to document or troubleshoot. If command -v points somewhere unexpected, stop and inspect that executable before relying on its behaviour.
2. Choose a stream and mode
Pass one or more of -i, -o and -e immediately before the command. The mode is the value after the equals sign, or the next argument in a form such as -o L.
Lrequests line buffering. It is valid for output and error, but not standard input.0requests an unbuffered stream.- A size such as
4Krequests full buffering with a 4096-byte buffer. Decimal suffixes such asKBuse powers of 1000;KandKiBare 1024 bytes.
For a live text pipeline, start with line-buffered output:
stdbuf -oL COMMAND ARGUMENTS...
Do not use -iL. The installed help explicitly rejects line buffering for standard input. If you need input unbuffered, use -i0 instead.
3. Apply line buffering in a pipeline
A typical use is to put stdbuf in front of the stage that is holding output. This is the form documented by the local manpage:
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
Here, cut is asked to flush each output line rather than waiting for a full block. tail -f continues following the file, while uniq removes adjacent duplicate names. Replace access.log with a readable log file; do not create or truncate a production log merely to test this command.
Checkpoint: run the pipeline against a test copy or a log you are already authorised to read. In a second terminal, append a harmless test line if changing that test file is safe. You should see the corresponding first field arrive promptly when the complete line reaches the pipeline. Press Ctrl+C to stop tail -f; no persistent setting has been changed.
The final stage matters. If uniq is also delaying its output in your workload, give that stage its own buffering setting:
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | stdbuf -oL uniq
Use this only when the downstream command is compatible with stdbuf. Buffering is a property of each process and stream, not of the pipe as a whole.
4. Test a mode without changing files
For a quick smoke test, run a short-lived shell command. This confirms that stdbuf can start the command and that the command's exit status is returned:
$ stdbuf -o0 sh -c 'printf "%s" ready'
ready$ echo "exit status: $?"
exit status: 0
The missing newline after ready is deliberate: the child printed exactly the requested text. -o0 does not add newlines or otherwise change the command's output. It changes the buffering mode for standard output.
When you need a newline for readability, make the command print one:
$ stdbuf -oL sh -c 'echo line-one'
line-one
These checks do not prove that every program honours stdbuf. They only verify the wrapper invocation and the child result.
5. Know the boundary: stdbuf is not universal
stdbuf modifies the standard streams used by a command. A program can replace those settings itself, in which case the program wins. The manpage calls out tee as an example that may adjust its own buffering.
Some tools do not use standard C streams for their input and output. The local documentation names dd and cat as examples that are therefore unaffected by stdbuf settings. If a command is one of these cases, adding stdbuf is not a fix. Check that command's own options or documentation instead.
This boundary is a common distraction trap: a pipeline may contain several processes, and changing one process cannot force all the others to flush. Put the wrapper directly before the command whose stream is delayed, then test each stage separately where possible.
6. Handle errors and exit statuses
stdbuf reports its own failures distinctly. Status 125 means the stdbuf command failed. Status 126 means the command was found but could not be invoked, and status 127 means it could not be found. Otherwise, stdbuf returns the child command's status.
Capture the status immediately after the command if a script needs to distinguish these cases:
stdbuf -oL /path/to/COMMAND --safe-test-argument
status=$?
echo "command status: $status"
case "$status" in
125) echo 'stdbuf itself failed' >&2; exit 125 ;;
126) echo 'command found but could not be invoked' >&2; exit 126 ;;
127) echo 'command was not found' >&2; exit 127 ;;
esac
exit "$status"
Replace both placeholders with a command and argument you have already tested. Quote paths and values that may contain spaces. Do not pass untrusted text as an option string, and do not use a production service as the first test.
7. Treat explicit buffer sizes as a special case
Line and unbuffered modes are the useful starting points for interactive pipelines. The local manpage warns that, on glibc platforms, specifying a buffer size and therefore requesting full buffering has undefined operation. This machine uses glibc, so do not make a sized mode such as -o4K part of a reliability-critical workflow without testing the exact program and platform.
If you are investigating an existing sized invocation, record the command, coreutils version and libc environment before changing it. A safe rollback is simply to remove the stdbuf wrapper and run the original command again. If you changed a service unit, wrapper script or scheduled job outside these examples, restore the previous file from your normal configuration-management copy and restart the service only during an approved maintenance window.
Done means
- You checked that the installed executable is GNU coreutils 9.4.
- You selected the correct stream:
-ofor output,-efor error and-i0for unbuffered input. - You used line buffering on the pipeline stage that was actually delaying output.
- You know that programs such as
tee,ddandcatcan override or bypass stdbuf. - You checked the returned status and can distinguish stdbuf failures from the child's result.
- You tested without changing persistent configuration, services or production data.