Chapter 19Lesson 02~100 minutes

Streaming versus Buffering Large Data

Large data does not belong in shell variables by default. Streaming lets Bash coordinate records incrementally, while buffering remains useful when an algorithm genuinely needs the complete dataset.

AdvancedPerformance & parallelismHands-on lab

Learning objectives

By the end of this lesson

  • Explain streaming and buffering tradeoffs.
  • Avoid capturing unnecessarily large output.
  • Use pipelines and temporary files appropriately.
  • Choose safe record delimiters.
  • Understand pipeline backpressure.

1. Streaming processes records incrementally

A streaming workflow handles records as they arrive instead of loading the entire dataset first. This lowers peak memory and can reduce latency for large files, logs, and command output.

Streaming data flow
flowchart LR
  I["input"] --> R1["record"]
  R1 --> P["process"]
  P --> O["output"]
  I --> R2["next record"]

2. Buffering is useful when the full dataset is genuinely needed

mapfile -t lines < small-input.txt
printf 'count=%d\n' "${#lines[@]}"

If later logic needs random access, repeated traversal, or full-dataset decisions and the input is small enough, buffering can simplify the design.

3. Avoid giant command substitutions

generate_large_report |
while IFS= read -r line; do
  process "$line"
done

Capturing a huge report into one variable increases memory use and delays downstream processing until generation is complete.

4. Pipelines are natural streaming boundaries

journalctl -u myapp --since today |
grep 'ERROR' |
awk '{ count[$5]++ } END { for (k in count) print k, count[k] }'

Each stage can begin work before the upstream producer finishes.

5. Some operations inherently need working storage

Sorting, deduplication, grouping, and joins may require large working sets. Use tools designed for those operations rather than building huge Bash arrays.

6. Temporary files are a legitimate scalability tool

tmp=$(mktemp) || exit 1
trap 'rm -f -- "$tmp"' EXIT

generate_large_report > "$tmp"
validate_report "$tmp"
compress_report "$tmp"

A temporary file is useful when several passes are required or downstream tools need seekable input.

7. tee observes a stream without fully buffering it

set -o pipefail

generate_data |
tee raw.log |
transform |
consume

With pipefail, logging a stream does not have to hide upstream failure.

8. Streaming safety depends on record boundaries

find artifacts -type f -print0 |
while IFS= read -r -d '' file; do
  process "$file"
done

For Unix pathnames, NUL-delimited records are robust because NUL cannot occur inside a pathname.

9. Pipes provide backpressure

When a consumer is slower than its producer, pipe buffers eventually fill and the producer blocks. This prevents unlimited memory growth and is one reason streaming pipelines scale well.

10. Hands-on lab: buffered versus streaming input

mkdir -p "$HOME/devops-academy/bash/chapter19/lesson02"
cd "$HOME/devops-academy/bash/chapter19/lesson02"

seq 1 100000 > numbers.txt

cat > buffered.sh <<'EOF'
#!/usr/bin/env bash
mapfile -t numbers < numbers.txt
sum=0
for n in "${numbers[@]}"; do
  ((sum += n))
done
printf 'sum=%d\n' "$sum"
EOF

cat > streaming.sh <<'EOF'
#!/usr/bin/env bash
sum=0
while IFS= read -r n; do
  ((sum += n))
done < numbers.txt
printf 'sum=%d\n' "$sum"
EOF

chmod u+x buffered.sh streaming.sh

time bash buffered.sh
time bash streaming.sh

Verification checklist

11. Knowledge check

Question 1. What is the main advantage of streaming?

Question 2. When is buffering appropriate?

Question 3. Why might a temporary file beat a variable?

Question 4. What is pipeline backpressure?

12. Summary

Stream data when you can process it incrementally, buffer when the algorithm needs the whole dataset, and use temporary files for large multi-pass workflows. Match record boundaries and buffering behavior to the data.

13. Further reading

  • GNU Bash Reference Manual — pipelines and mapfile.
  • GNU Coreutils documentation — tee, sort, uniq.
  • Unix pipe and buffering documentation.
  • GNU findutils documentation for NUL-delimited records.
Next lesson

Profiling Shell Scripts with time and Timestamps

Continue Chapter 19 by making Bash performance and concurrency decisions evidence-driven and bounded.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.