patternbashModerate
Command substitution: $() vs backticks and handling newlines
Viewed 0 times
command substitutionbackticksdollar parenoutput capturetrailing newlinesubshell
Problem
Legacy backtick syntax is hard to read, hard to nest, and inconsistent with quoting rules. Additionally, command substitution strips trailing newlines from output, which silently corrupts data.
Solution
Always use $() for command substitution. Be aware that trailing newlines are stripped.
# Modern: use $()
date=$(date +%F)
files=$(find . -name '*.sh')
# Nested (impossible cleanly with backticks)
owner=$(stat -c '%U' "$(which python3)")
# Preserving trailing newlines: add a sentinel
output=$(cmd; echo x)
output="${output%x}" # strip sentinel
# Check if command produced output
if [[ -n "$(some_command)" ]]; then ...
# Modern: use $()
date=$(date +%F)
files=$(find . -name '*.sh')
# Nested (impossible cleanly with backticks)
owner=$(stat -c '%U' "$(which python3)")
# Preserving trailing newlines: add a sentinel
output=$(cmd; echo x)
output="${output%x}" # strip sentinel
# Check if command produced output
if [[ -n "$(some_command)" ]]; then ...
Why
$() creates a subshell, runs the command, captures its stdout, and strips trailing newlines. Backticks do the same but with inconsistent quoting (backslashes are interpreted differently) and no clean nesting.
Gotchas
- Command substitution strips ALL trailing newlines, not just one
- To preserve newlines, append a character inside $() and strip it after: $(cmd; echo .)
- The subshell in $() runs in a separate process — variable changes don't propagate out
- Backticks require escaping backslashes differently and cannot be cleanly nested
- Large output in $() buffers in memory — pipe directly if output could be huge
Code Snippets
Command substitution best practices
# GOOD: modern syntax
today=$(date +%Y-%m-%d)
echo "Today: $today"
# BAD: legacy backticks (hard to nest)
today=`date +%Y-%m-%d`
# Nested substitution — impossible cleanly with backticks
py_path=$(dirname "$(which python3)")
# Trailing newline preservation trick
result=$(printf 'line1\nline2\n'; echo -n x)
result="${result%x}"
printf '%s' "$result" | wc -l # 2 (newlines preserved)Context
Capturing command output into variables in bash scripts
Revisions (0)
No revisions yet.