$( ) — capture command output
now="$(date +%Y-%m-%d)"
files="$(find . -name '*.py' | wc -l)"
echo "$files Python files as of $now"$(...) runs the command, captures stdout, and substitutes the value (with trailing newlines trimmed). Always quote the result: "$(cmd)" — without quotes the value is word-split.
Backticks (legacy)
You'll see `cmd` in old scripts. Same effect, but harder to nest and easier to confuse with single quotes. Use $( ) in new code; backticks are deprecated in style guides.
(( )) — arithmetic
i=0
((i++))
((sum = a + b * 2))
((i < 10)) && echo 'still small'Inside (( )) you don't need $ on variable names. Operators: + - * / % ** and C-style ++ -- && ||. The exit code is 0 if the result is non-zero, 1 if zero — opposite of typical C, but consistent with shell truthiness.
$(( )) — arithmetic substitution
echo "$((1 + 2))" # 3
echo "file_$((i + 1)).txt"Computes the value and substitutes the result. Common in filename generation and counters.
Bash 5 doesn't do floating-point
Shell arithmetic is integer only. For floats, pipe to bc -l or awk 'BEGIN{print 3.14*2}'. Most scripts don't need floats; if yours does, it's probably time to switch to Python.
Command substitution removes trailing newlines
That is convenient for one-line results but cannot preserve arbitrary text endings, and shell variables cannot contain NUL bytes. Do not capture an arbitrary filename stream into one variable.
Arithmetic commands produce an exit status
(( expression )) returns 1 for zero and 0 otherwise, so ((i++)) can stop under set -e when i starts at zero. Choose $((...)) for a value and ((...)) when status semantics are intended.