Skip to main content

How to Trim Whitespace from String in Bash

• 3 min read
bash string manipulation trim whitespace

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

MethodSpeedBest ForPurity
xargsVery fastSimple trimmingExternal command
Parameter expansionVery fastPure BashBuilt-in only
sedFastComplex patternsExternal command
trVery fastCharacter removalExternal command
printf %sVery fastFormattingBuilt-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:

MethodSpeedMemoryPortable
xargsVery FastLowYes
Parameter ExpansionFastestLowYes
sedFastLowYes
awkFastLowYes

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" | xargs for simplest, most readable solution
  • Use parameter expansion for pure Bash without external commands
  • Use sed for complex patterns and file processing
  • Use awk when 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:]]*$//'
#!/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")"