Hidden Gems: Little-Known Bash Features

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
Pro Tip: Use ${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
Safety Note: Use :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
Productivity Boost: Add useful shopt options to your .bashrc file, such as shopt -s globstar for recursive globbing with **.