How to Modify Stream Buffering in Linux Using the stdbuf Command

When chaining multiple commands together in Linux shell pipelines (such as grep, sed, awk, and cut), you may encounter unexpected delays where data appears frozen and fails to display on the terminal until the pipeline terminates or large chunks of data accumulate. This behaviour is governed by the standard C library’s (glibc) internal stream buffering mechanisms.

By default, when a command outputs directly to an interactive terminal, glibc uses line buffering (flushing text line by line). However, when stdout is redirected into a pipe or a file, glibc automatically switches to block buffering (accumulating 4096 or 8192 bytes before emitting data). The standard GNU coreutil stdbuf allows administrators and script authors to override these buffering defaults on the fly without modifying source code.

Understanding Standard I/O Buffering Types

Standard C library streams maintain three distinct buffering modes:

  • Unbuffered (0 bytes): Characters written to the stream are transmitted immediately to the destination kernel file descriptor.
  • Line Buffered: Output bytes are held in memory and flushed only when a newline character (\n) is written, or when the buffer fills.
  • Block Buffered (Fully Buffered): Output is accumulated until a fixed-size memory buffer (typically 4 KB or 8 KB) is completely full, maximizing throughput for batch disk operations at the expense of interactive latency.

Overriding Stream Buffering with stdbuf

The stdbuf command modifies the buffering rules for standard input (-i), standard output (-o), and standard error (-e) before executing the target binary:

stdbuf OPTION... COMMAND

Buffering arguments include:

  • 0: Sets the stream to unbuffered mode.
  • L: Sets the stream to line-buffered mode (valid only for output streams).
  • <number>: Sets a custom buffer size in bytes, kilobytes (K), or megabytes (M) (e.g. 1024 or 1M).

Fixing Delayed Real-Time Log Processing Pipelines

A classic pipeline latency hurdle occurs when streaming a log file through tail -f, filtering with grep, and formatting with awk:

tail -f /var/log/nginx/access.log | grep --line-buffered "404" | awk '{print $1, $7}'

While grep has its own --line-buffered flag, other tools (like sed, tr, or custom binary executables) do not. Wrapping the middle command with stdbuf resolves the bottleneck instantly:

tail -f /var/log/syslog | stdbuf -oL cut -d' ' -f1-5 | grep "CRON"

The -oL flag forces cut to emit text after every single line, preventing log events from remaining trapped in memory.

Eliminating Buffering for Continuous Data Logging

When running long-duration diagnostic tools whose standard output is redirected into a log file, an unexpected crash or system reboot can cause buffered, unwritten lines to be lost permanently. To enforce immediate, zero-latency disk flushing:

stdbuf -o0 ping 8.8.8.8 > ping_latency.log

Setting -o0 disables output buffering entirely. Every individual ICMP reply is committed to ping_latency.log immediately upon receipt.

Modifying Standard Error Buffering

While standard error (stderr) is unbuffered by default on most POSIX systems, certain non-standard runtimes or third-party binaries configure block buffering on error streams. To guarantee immediate error output in CI/CD build scripts:

stdbuf -e0 ./custom_build_worker.sh

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.