Skip to content
AgileLogics
5 min read

Performance

Prerequisites: The text toolkit: sort, uniq, cut, tr, and friends, Subshells, grouping, and process substitution

Bash is fast at starting programs and gluing them together, and slow at doing heavy work itself. The main performance rule: avoid running external programs thousands of times inside a loop.

Loops that start a process per line are slow

seq 1 2000 > numbers.txt

# Slow: one `expr` process per line
time_slow() { local t=0; while read -r n; do t=$(expr "$t" + "$n"); done < numbers.txt; echo "$t"; }

# Faster: Bash arithmetic, no extra processes
time_fast() { local t=0; while read -r n; do (( t += n )); done < numbers.txt; echo "$t"; }

# Fastest: one awk process for the whole file
time_awk() { awk '{ t += $1 } END { print t }' numbers.txt; }

time_slow
time_fast
time_awk
2001000
2001000
2001000

All three print the same total, but on a typical machine the first takes several seconds (2,000 process launches), the second a few milliseconds, and the third about the same — and awk stays fast on millions of lines, where the Bash loop would crawl.

Measure with time: time ./script.sh reports real (wall-clock), user, and system time.

Guidelines

  • Use builtins instead of external commands in loops: $(( )) instead of expr, ${var##*/} instead of basename, [[ ]] instead of grep for single strings, printf -v instead of $(printf ...).
  • Process whole files with one tool (awk, sed, grep, sort) rather than looping line by line in Bash.
  • Avoid needless subshells — each $(...) forks a process.
  • Batch work: find ... -exec cmd {} + instead of \;, and xargs instead of a loop calling a command per file.
  • Parallelize independent work with xargs -P (previous lessons).

When Bash is the wrong tool

If a task needs heavy computation, large in-memory data structures, or complex parsing, a language like Python will be faster to write and to run. Bash is at its best orchestrating other programs.