Bash Command Substitution
Command substitution allows you to capture the output of a command and use it as part of another command or assignment.
Basic Syntax
There are two syntaxes for command substitution in Bash:
# Original backtick syntax (legacy)
`command`
# Modern POSIX syntax (preferred)
$(command)
Simple Examples
# Store command output in a variable
files=$(ls)
count=$(wc -l < file.txt)
# Use command output directly
echo "Today is $(date)"
echo "You are running $(uname -s) version $(uname -r)"
Nested Command Substitution
You can nest command substitutions when needed:
# Get the name of the largest file in directory
largest=$(ls -S $(pwd) | head -1)
echo "Largest file is: $largest"
Command Substitution in Loops
# Process each line from a command's output
while read -r line; do
echo "Processing: $line"
done < <(grep "pattern" *.txt)
# Loop through files found by find command
for file in $(find . -name "*.txt"); do
echo "Found text file: $file"
done
Command Substitution vs. Pipes
Command substitution captures output for later use, while pipes connect commands directly:
# Using command substitution
contents=$(cat file.txt)
echo "$contents" | grep "pattern"
# Using pipes directly
cat file.txt | grep "pattern"
Process Substitution
A related concept that treats command output as a file:
# Compare sorted versions of two files
diff <(sort file1.txt) <(sort file2.txt)
# Merge sorted output from two commands
sort -m <(command1) <(command2) > merged.txt
Best Practices
- Prefer
$(...)
over backticks for better readability and nesting - Always quote command substitutions to preserve whitespace:
"$(command)"
- For complex commands, consider using temporary variables for clarity
- Be aware that command substitution removes trailing newlines
- For multiline output, use double quotes when echoing:
echo "$var"
Advanced Examples
# Generate a dynamic filename
backup_file="backup-$(date +%Y%m%d).tar.gz"
tar -czf "$backup_file" /path/to/files
# Create a menu from command output
select option in $(ls *.txt); do
echo "You selected $option"
break
done
# Count occurrences in multiple files
total=$(grep -c "error" $(find /var/log -name "*.log") | awk '{sum += $1} END {print sum}')
echo "Total errors found: $total"
Common Pitfalls
- Forgetting to quote command substitutions, leading to word splitting
- Using command substitution when a pipe would be more efficient
- Assuming command substitution works the same in all shells (some features are Bash-specific)
- Using command substitution in performance-critical sections (it creates subshells)