Skip to main content

How to Split String by Delimiter in Bash

• 3 min read
bash string manipulation split string delimiter array

Quick Answer: Split a String by Delimiter in Bash

To split a string by delimiter in Bash, use the read command with IFS (Internal Field Separator): IFS=',' read -ra array <<< "$string". This stores each delimited part in an array that you can iterate through. It’s the fastest, most reliable method for string splitting.

Quick Comparison: String Splitting Methods

MethodSpeedBest ForComplexity
read with IFSFastestSimple splits, arraysVery simple
awk with -FVery fastCSV/structured dataSimple
tr + loopFastConverting delimitersSimple
Parameter expansionFastKnown number of fieldsModerate
grep + sedMediumComplex patternsComplex

Bottom line: Use read with IFS for most cases. Use awk when processing structured data files.


Method 1: Using read with IFS (The Standard Approach)

The read command with IFS (Internal Field Separator) is the Bash-native solution for splitting strings. It’s fast, reliable, and requires no external commands. When you set IFS to your delimiter, read automatically splits on that character and populates an array.

Split String into an Array

Here’s the fundamental pattern—set the delimiter, then read into an array:

# Split by comma into array
text="apple,banana,orange"
IFS=',' read -ra fruits <<< "$text"

for fruit in "${fruits[@]}"; do
  echo "$fruit"
done

# Output:
# apple
# banana
# orange

Let’s break down what’s happening: IFS=',' sets the delimiter to comma. read -ra fruits reads input into an array named fruits (the a flag means array, r means raw—don’t interpret backslashes). The <<< "$text" is a here-string that passes your text to read.

Split with Different Delimiters

The same pattern works with any delimiter—colon, pipe, semicolon, whatever you need:

text="one:two:three"
IFS=':' read -ra parts <<< "$text"

echo "${parts[0]}"  # Output: one
echo "${parts[1]}"  # Output: two
echo "${parts[2]}"  # Output: three

Each element of the array is now accessible by index. This is useful for processing any delimited data.

When to Use read with IFS

Use this method when:

  • You’re splitting strings into arrays
  • You need the fastest pure-Bash solution
  • You want simplicity and readability
  • You’re processing text stored in variables
  • You need to iterate through the parts

Avoid it when:

  • You’re processing files (use awk instead—it’s more efficient for files)
  • You need complex pattern matching (use awk or sed)
  • The delimiter might appear in quoted fields (use awk with proper quoting)

Method 2: Split into Variables

Assign parts directly to variables instead of an array.

# Split into specific variables
text="apple,banana,orange"
IFS=',' read -r fruit1 fruit2 fruit3 <<< "$text"

echo "First: $fruit1"
echo "Second: $fruit2"
echo "Third: $fruit3"

# Output:
# First: apple
# Second: banana
# Third: orange

Example with CSV:

csv_line="John,Doe,30,Engineer"
IFS=',' read -r first last age job <<< "$csv_line"

echo "Name: $first $last"
echo "Age: $age"
echo "Job: $job"

Method 3: Split with Preservation of IFS

Store original IFS and restore it afterward.

text="apple,banana,orange"
oldIFS=$IFS          # Save original IFS
IFS=','
read -ra parts <<< "$text"
IFS=$oldIFS          # Restore original IFS

for part in "${parts[@]}"; do
  echo "$part"
done

Method 4: Using awk

awk is powerful for more complex splitting patterns.

# Split by comma and print fields
text="apple,banana,orange"
echo "$text" | awk -F',' '{print $1, $2, $3}'
# Output: apple banana orange

# Access individual fields
echo "$text" | awk -F',' '{print "First: " $1}'
# Output: First: apple

Example:

$ echo "John,30,Engineer" | awk -F',' '{print $1, "is", $3}'
John is Engineer

Method 5: Using tr and Loop

Convert delimiter to newline and iterate.

text="apple:banana:orange"
echo "$text" | tr ':' '\n' | while read fruit; do
  echo "Fruit: $fruit"
done

# Output:
# Fruit: apple
# Fruit: banana
# Fruit: orange

Method 6: Split with Regular Expressions

Use more complex patterns for splitting.

# Split by whitespace (multiple spaces)
text="apple    banana   orange"
IFS=' ' read -ra fruits <<< "$text"

# Split by multiple characters
text="apple||banana||orange"
IFS='||' read -ra fruits <<< "$text"

Practical Examples

Example 1: Parse CSV Data

#!/bin/bash

csv_line="$1"

IFS=',' read -ra fields <<< "$csv_line"

echo "Total fields: ${#fields[@]}"

for i in "${!fields[@]}"; do
  echo "Field $i: ${fields[$i]}"
done

Usage:

$ bash script.sh "John,Doe,30,Engineer"
Total fields: 4
Field 0: John
Field 1: Doe
Field 2: 30
Field 3: Engineer

Example 2: Process File Path

#!/bin/bash

file_path="$1"

# Split path by /
IFS='/' read -ra parts <<< "$file_path"

echo "Path parts:"
for part in "${parts[@]}"; do
  [ -n "$part" ] && echo "  - $part"
done

# Get filename (last part)
filename="${parts[-1]}"
echo "Filename: $filename"

Usage:

$ bash script.sh "/home/user/documents/report.pdf"
Path parts:
  - home
  - user
  - documents
  - report.pdf
Filename: report.pdf

Example 3: Parse Configuration

#!/bin/bash

# Parse key=value configuration
config_line="$1"

IFS='=' read -r key value <<< "$config_line"

key=$(echo "$key" | xargs)      # Trim
value=$(echo "$value" | xargs)  # Trim

echo "Key: $key"
echo "Value: $value"

Usage:

$ bash script.sh "db_host = localhost"
Key: db_host
Value: localhost

Example 4: Split and Process CSV File

#!/bin/bash

csv_file="$1"

while IFS=',' read -ra fields; do
  # Skip header
  [ "${fields[0]}" = "name" ] && continue

  name="${fields[0]}"
  age="${fields[1]}"
  city="${fields[2]}"

  printf "%-15s %-3s %s\n" "$name" "$age" "$city"
done < "$csv_file"

Example 5: Split Command Arguments

#!/bin/bash

# Split comma-separated list of files
file_list="$1"

IFS=',' read -ra files <<< "$file_list"

echo "Processing files:"
for file in "${files[@]}"; do
  file=$(echo "$file" | xargs)  # Trim whitespace
  if [ -f "$file" ]; then
    echo "✓ $file"
  else
    echo "✗ $file (not found)"
  fi
done

Usage:

$ bash script.sh "file1.txt, file2.txt, file3.txt"
Processing files:
✓ file1.txt
✓ file2.txt
✓ file3.txt

Example 6: Split URL Components

#!/bin/bash

url="$1"

# Remove protocol
IFS='://' read -r protocol rest <<< "$url"
echo "Protocol: $protocol"

# Split rest into host and path
IFS='/' read -r host path <<< "$rest"
echo "Host: $host"
echo "Path: /$path"

# Extract port if exists
if [[ "$host" =~ : ]]; then
  IFS=':' read -r hostname port <<< "$host"
  echo "Hostname: $hostname"
  echo "Port: $port"
fi

Usage:

$ bash script.sh "https://example.com:8080/api/users"
Protocol: https
Host: example.com:8080
Path: /api/users
Hostname: example.com
Port: 8080

Example 7: Function for String Splitting

#!/bin/bash

# Reusable function
split_string() {
  local string="$1"
  local delimiter="${2:- }"  # Default: space
  local -n result=$3          # Reference to result array

  IFS="$delimiter" read -ra result <<< "$string"
}

# Usage
split_string "apple,banana,orange" "," fruits
echo "Fruits: ${fruits[@]}"

split_string "one:two:three" ":" items
echo "Items: ${items[@]}"

Advanced Techniques

Variable-Length Splitting

#!/bin/bash

# Split but keep delimiter count
text="apple,,banana,orange"

IFS=',' read -ra parts <<< "$text"

echo "Parts (including empty):"
for i in "${!parts[@]}"; do
  echo "[$i] = '${parts[$i]}'"
done

Conditional Splitting

#!/bin/bash

text="$1"
delimiter="${2:-,}"

# Split only if delimiter exists
if [[ "$text" == *"$delimiter"* ]]; then
  IFS="$delimiter" read -ra parts <<< "$text"
  echo "Split into ${#parts[@]} parts"
else
  echo "No delimiter found"
fi

Performance Comparison

For splitting strings:

MethodSpeedMemoryBest For
read with IFSFastestLowMost cases
awkVery FastMediumComplex patterns
tr + loopMediumLowSimple cases

Best choice: Use read -ra array <<< "$string" for most cases.

Important Considerations

Preserving Empty Fields

# Splits correctly including empty fields
text="a,,c"
IFS=',' read -ra parts <<< "$text"

echo "${#parts[@]}"  # 3 (includes empty middle)
echo "[${parts[1]}]" # [] (empty field preserved)

Whitespace Handling

# With leading/trailing spaces
text="  apple , banana , orange  "
IFS=',' read -ra parts <<< "$text"

# Note: parts contain spaces
echo "[${parts[0]}]"  # [  apple ]

# Trim if needed
for part in "${parts[@]}"; do
  part=$(echo "$part" | xargs)
  echo "[$part]"
done

Special Characters in Delimiter

# Multi-character delimiter
text="apple||banana||orange"
IFS='||' read -ra parts <<< "$text"

# Regex-like splitting (use awk instead)
text="apple123banana456orange"
echo "$text" | awk -F'[0-9]+' '{print $1, $2, $3}'

Key Points

  • Use IFS='delimiter' read -ra array for splitting into array
  • Use read -r var1 var2 var3 to split into variables
  • Always quote the string: <<< "$string"
  • Remember IFS changes only last for the read command
  • Empty fields are preserved in arrays
  • Trim whitespace afterward if needed
  • Use awk for complex pattern-based splitting

Quick Reference

# Split by delimiter into array
IFS=',' read -ra array <<< "one,two,three"

# Split by delimiter into variables
IFS=',' read -r var1 var2 var3 <<< "one,two,three"

# Split with different delimiter
IFS=':' read -ra parts <<< "$string"

# Split with pipe
IFS='|' read -ra fields <<< "$string"

# Access array
echo "${array[0]}"      # First element
echo "${array[@]}"      # All elements
echo "${#array[@]}"     # Array length
#!/bin/bash

string="$1"
delimiter="${2:-, }"  # Default: comma

# Split into array
IFS="$delimiter" read -ra parts <<< "$string"

# Process parts
echo "Total parts: ${#parts[@]}"

for part in "${parts[@]}"; do
  # Trim whitespace
  part=$(echo "$part" | xargs)
  echo "Processing: $part"
done