Bash is one of the most widely used shells in the Unix world, yet many of its most powerful features remain underutilized. This article explores several lesser-known capabilities that can significantly enhance your command-line productivity.
1. Brace Expansion for Rapid File Creation
While many users know about basic brace expansion like {1..5}, few realize its full potential for complex patterns and nested structures.
# Create a complete project structure in one line
mkdir -p project/{src,tests,docs}/{js,css,img}
# Generate sequential files with padding
touch file_{001..100}.txt
# Combine multiple expansions
echo {a,b,c}{1,2,3} # outputs: a1 a2 a3 b1 b2 b3 c1 c2 c3
2. Parameter Expansion Tricks
Bash's parameter expansion goes far beyond simple variable substitution, offering powerful string manipulation capabilities.
# Default values
echo ${undefined_var:-"default value"}
# Remove file extensions
filename="document.pdf"
echo ${filename%.pdf} # outputs: document
# Replace substrings
path="/home/user/documents"
echo ${path/home/root} # outputs: /root/user/documents
# Get string length
echo ${#filename} # outputs: 12
# Substring extraction
echo ${filename:0:8} # outputs: document
${var^^} to convert to uppercase and ${var,,} to convert to lowercase (Bash 4+).
3. Process Substitution
Process substitution allows you to treat command output as a file, enabling powerful data comparisons and manipulations.
# Compare output of two commands
diff <(ls dir1) <(ls dir2)
# Use multiple inputs for a command
paste <(seq 1 5) <(seq 6 10)
# Read from a process
while read line; do
echo "Line: $line"
done < <(find . -name "*.txt")
4. The Powerful [[ Test Command
The double-bracket test command offers significant advantages over the traditional single bracket, including pattern matching and logical operators.
# Pattern matching without quotes
if [[ $filename == *.txt ]]; then
echo "Text file detected"
fi
# Regex matching
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid email format"
fi
# Logical operators without escaping
if [[ $age -gt 18 && $age -lt 65 ]]; then
echo "Working age"
fi
5. Here Strings and Here Documents
These features provide elegant ways to pass multi-line input to commands.
# Here string (<<<)
tr '[:lower:]' '[:upper:]' <<< "convert this to uppercase"
# Here document
cat << EOF > config.txt
server: localhost
port: 8080
timeout: 30
EOF
# Suppress tab indentation with <<-
cat <<- EOF
This text can be indented
in your script for readability
EOF
6. Command Grouping and Subshells
Group commands to control execution scope and environment variables.
# Grouping with { } executes in current shell
{ cd /tmp; ls; } > output.txt
# Subshell with ( ) creates isolated environment
(cd /tmp && rm -rf test_dir) # doesn't change current directory
# Combine with redirections
{ echo "Header"; cat data.txt; echo "Footer"; } > complete.txt
7. The ! History Expansion
Navigate and reuse your command history efficiently with these operators.
# Execute last command starting with 'git'
!git
# Get the last argument of previous command
ls /var/log/nginx/access.log
cat !$ # equivalent to: cat /var/log/nginx/access.log
# Get all arguments from previous command
mv !*
# Replace text in previous command
^old^new # replaces first occurrence
:p to preview history expansions without executing: !git:p
8. Array Manipulation
Bash arrays offer more functionality than many users realize.
# Declare and populate arrays
files=(*.txt)
numbers=({1..10})
# Array slicing
echo ${files[@]:2:3} # elements 2-4
# Array length
echo ${#files[@]}
# Remove elements matching pattern
filtered=(${files[@]/*test*/})
# Append to array
files+=("new_file.txt")
9. Automatic Job Control
Manage background processes more effectively.
# Run in background and disown (continues after shell closes)
long_running_task &
disown
# Wait for specific background job
./script1.sh & pid=$!
# do other work
wait $pid
# Run command only if previous succeeded
make && make install
# Run regardless of previous result
make; make install
10. Extended Globbing
Enable pattern matching capabilities that rival regular expressions.
# Enable extended globbing first
shopt -s extglob
# Match everything except pattern
ls !(*.txt) # all files except .txt
# Match zero or one occurrence
ls file?(s).log # matches file.log and files.log
# Match one or more
ls file+(s).log # matches files.log, filess.log, etc.
# Match zero or more
ls @(*.jpg|*.png) # matches .jpg OR .png files
.bashrc file, such as shopt -s globstar for recursive globbing with **.