How to Trim Whitespace from String in Bash
Quick Answer: Trim Whitespace from a String
To remove leading and trailing whitespace from a string in Bash, use xargs: echo "$text" | xargs. For a pure-Bash solution, use parameter expansion with regex: ${text//[[:space:]]/ }. Both are simple and effective for cleaning user input.
Quick Comparison: Whitespace Trimming Methods
| Method | Speed | Best For | Purity |
|---|---|---|---|
| xargs | Very fast | Simple trimming | External command |
| Parameter expansion | Very fast | Pure Bash | Built-in only |
| sed | Fast | Complex patterns | External command |
| tr | Very fast | Character removal | External command |
| printf %s | Very fast | Formatting | Built-in only |
Bottom line: Use xargs for simplicity, use parameter expansion for pure Bash.
Remove leading and trailing whitespace from strings in Bash. Whitespace trimming is essential for input validation, data cleaning, and string processing in many scripts.
Method 1: Using xargs (Simplest)
The xargs method is the simplest and most readable, though it uses an external command.
text=" Hello World "
trimmed=$(echo "$text" | xargs)
echo "[$trimmed]" # Output: [Hello World]
# Works with any amount of whitespace
text=" text with multiple spaces "
trimmed=$(echo "$text" | xargs)
echo "[$trimmed]" # Output: [text with multiple spaces]
Example with variables:
$ text=" test "
$ trimmed=$(echo "$text" | xargs)
$ echo "[$trimmed]"
[test]
Method 2: Using Parameter Expansion (Pure Bash)
No external commands needed, but syntax is complex.
# Remove leading and trailing whitespace
text=" Hello World "
trimmed=${text#${text%%[![:space:]]*}}
trimmed=${trimmed%${trimmed##*[![:space:]]}}
echo "[$trimmed]" # Output: [Hello World]
Breaking it down:
# Step 1: Remove leading whitespace
trimmed=${text#${text%%[![:space:]]*}}
# ${text%%[![:space:]]*} = " " (all leading spaces)
# ${text#...} = remove that prefix
# Step 2: Remove trailing whitespace
trimmed=${trimmed%${trimmed##*[![:space:]]}}
# ${trimmed##*[![:space:]]} = " " (all trailing spaces)
# ${trimmed%...} = remove that suffix
Method 3: Using sed
The sed command is powerful for pattern-based trimming.
# Trim leading and trailing whitespace
text=" Hello World "
trimmed=$(echo "$text" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
echo "[$trimmed]" # Output: [Hello World]
# Alternative pattern (simpler but less portable)
trimmed=$(echo "$text" | sed 's/^ *//;s/ *$//')
# For tabs and spaces
trimmed=$(echo "$text" | sed 's/^[ \t]*//;s/[ \t]*$//')
Example:
$ text=" test string "
$ echo "$text" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
test string
Method 4: Using awk
awk can trim whitespace with a simple one-liner.
# Trim both leading and trailing
text=" Hello World "
trimmed=$(echo "$text" | awk '{$1=$1};1')
echo "[$trimmed]" # Output: [Hello World]
# Explanation:
# $1=$1 forces awk to rebuild $0
# This removes leading/trailing spaces
# ;1 ensures the line is printed
Method 5: Remove Only Leading Spaces
Sometimes you need to trim only from one side.
text=" Hello World "
# Remove only leading whitespace
trimmed=${text#${text%%[^ ]*}}
echo "[$trimmed]" # Output: [Hello World ]
# Using sed
trimmed=$(echo "$text" | sed 's/^[[:space:]]*//')
echo "[$trimmed]" # Output: [Hello World ]
# Using awk
trimmed=$(echo "$text" | awk '{sub(/^[[:space:]]+/, ""); print}')
Method 6: Remove Only Trailing Spaces
text=" Hello World "
# Remove only trailing whitespace
trimmed=${text%${text##*[^ ]}}
echo "[$trimmed]" # Output: [ Hello World]
# Using sed
trimmed=$(echo "$text" | sed 's/[[:space:]]*$//')
echo "[$trimmed]" # Output: [ Hello World]
# Using awk
trimmed=$(echo "$text" | awk '{sub(/[[:space:]]+$/, ""); print}')
Practical Examples
Example 1: Trim User Input
#!/bin/bash
# Read user input and trim
read -p "Enter your name: " name
name=$(echo "$name" | xargs) # Trim whitespace
read -p "Enter your email: " email
email=$(echo "$email" | xargs)
echo "Hello, $name ($email)"
Output:
Enter your name: John Smith
Enter your email: john@example.com
Hello, John Smith (john@example.com)
Example 2: Trim File Lines
#!/bin/bash
# Trim whitespace from all lines in file
input_file="$1"
output_file="${input_file%.txt}_trimmed.txt"
# Method 1: Using sed
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' "$input_file" > "$output_file"
# Method 2: Using awk
awk '{gsub(/^[[:space:]]+|[[:space:]]+$/, ""); print}' "$input_file" > "$output_file"
echo "Trimmed file: $output_file"
Example 3: Function to Trim Strings
#!/bin/bash
# Reusable trim function
trim() {
local text="$1"
# Remove leading and trailing whitespace
echo "$text" | xargs
}
# Or pure Bash version
trim_pure() {
local text="$1"
text=${text#${text%%[![:space:]]*}}
text=${text%${text##*[![:space:]]}}
echo "$text"
}
# Usage
name=" John Doe "
echo "Trimmed: [$(trim "$name")]"
echo "Pure Bash: [$(trim_pure "$name")]"
Output:
Trimmed: [John Doe]
Pure Bash: [John Doe]
Example 4: Trim CSV Fields
#!/bin/bash
# Trim whitespace from CSV fields
csv_file="$1"
# Process CSV, trimming each field
awk -F',' '{
for (i=1; i<=NF; i++) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $i)
}
print $0
}' OFS=',' "$csv_file" > "${csv_file%.csv}_trimmed.csv"
echo "Trimmed CSV: ${csv_file%.csv}_trimmed.csv"
Example 5: Trim and Validate Input
#!/bin/bash
# Function to trim and validate input
validate_input() {
local input="$1"
local min_length="${2:-1}"
local max_length="${3:-100}"
# Trim whitespace
input=$(echo "$input" | xargs)
# Check if empty
if [ -z "$input" ]; then
echo "Error: Input cannot be empty"
return 1
fi
# Check length
if [ ${#input} -lt $min_length ]; then
echo "Error: Input too short (minimum $min_length chars)"
return 1
fi
if [ ${#input} -gt $max_length ]; then
echo "Error: Input too long (maximum $max_length chars)"
return 1
fi
echo "$input"
return 0
}
# Usage
read -p "Enter username: " username
if username=$(validate_input "$username" 3 20); then
echo "Username accepted: $username"
else
echo "Invalid username"
fi
Output:
Enter username: john
Username accepted: john
Example 6: Trim and Normalize Whitespace
#!/bin/bash
# Normalize: trim AND reduce multiple spaces to single space
normalize_whitespace() {
local text="$1"
# Trim and collapse multiple spaces
echo "$text" | xargs
# Or using sed:
# echo "$text" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/[[:space:]]\+/ /g'
}
# Usage
text=" This has multiple spaces "
echo "Original: [$text]"
echo "Normalized: [$(normalize_whitespace "$text")]"
Output:
Original: [ This has multiple spaces ]
Normalized: [This has multiple spaces]
Example 7: Trim Configuration File Values
#!/bin/bash
# Parse config file, trimming values
config_file="$1"
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ "$key" =~ ^#.*$ ]] && continue
[ -z "$key" ] && continue
# Trim whitespace from key and value
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
echo "Config: $key = $value"
done < "$config_file"
Input (config.conf):
# Database Configuration
DB_HOST = localhost
DB_PORT = 5432
DB_NAME = mydb
Output:
Config: DB_HOST = localhost
Config: DB_PORT = 5432
Config: DB_NAME = mydb
Performance Comparison
For trimming whitespace:
| Method | Speed | Memory | Portable |
|---|---|---|---|
| xargs | Very Fast | Low | Yes |
| Parameter Expansion | Fastest | Low | Yes |
| sed | Fast | Low | Yes |
| awk | Fast | Low | Yes |
Best choice: Use xargs for simplicity, parameter expansion for pure Bash.
Important Considerations
Distinguishing Whitespace Types
Different types of whitespace require different handling:
# Spaces only
text=" hello "
trimmed=${text#${text%%[^ ]*}}
trimmed=${trimmed%${trimmed##*[^ ]}}
# Spaces and tabs
text=" hello "
trimmed=$(echo "$text" | sed 's/^[ \t]*//;s/[ \t]*$//')
# All Unicode whitespace (using xargs)
trimmed=$(echo "$text" | xargs)
Performance with Large Strings
Parameter expansion can be slow with very long strings:
# For large strings, use sed or awk
if [ ${#text} -gt 10000 ]; then
trimmed=$(echo "$text" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
else
trimmed=${text#${text%%[![:space:]]*}}
trimmed=${trimmed%${trimmed##*[![:space:]]}}
fi
Preserving Internal Whitespace
Be careful not to remove internal whitespace:
text=" hello world "
# This removes leading/trailing but keeps internal spaces:
trimmed=$(echo "$text" | xargs)
echo "[$trimmed]" # Output: [hello world] (note single space)
# To preserve exact internal spacing:
trimmed=${text#${text%%[![:space:]]*}}
trimmed=${trimmed%${trimmed##*[![:space:]]}}
echo "[$trimmed]" # Output: [hello world]
Key Points
- Use
echo "$text" | xargsfor simplest, most readable solution - Use parameter expansion for pure Bash without external commands
- Use
sedfor complex patterns and file processing - Use
awkwhen already processing text - Watch out for tabs vs spaces
- Remember xargs collapses internal whitespace
- Test with various whitespace types in your data
Quick Reference
# Simplest: trim both sides
echo "$text" | xargs
# Pure Bash: trim both sides
text=${text#${text%%[![:space:]]*}}
text=${text%${text##*[![:space:]]}}
# Sed: trim both sides
sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
# Awk: trim both sides
awk '{$1=$1};1'
# Lead only
sed 's/^[[:space:]]*///
# Trailing only
sed 's/[[:space:]]*$//'
Recommended Pattern
#!/bin/bash
# Simple and portable approach
trim() {
echo "$1" | xargs
}
# Pure Bash version (no external command)
trim_bash() {
local text="$1"
text=${text#${text%%[![:space:]]*}}
text=${text%${text##*[![:space:]]}}
echo "$text"
}
# Usage
name=" John Doe "
echo "Trimmed: $(trim "$name")"