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 ofexpr,${var##*/}instead ofbasename,[[ ]]instead ofgrepfor single strings,printf -vinstead 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\;, andxargsinstead 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.