How to Split String by Delimiter in Bash
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
| Method | Speed | Best For | Complexity |
|---|---|---|---|
| read with IFS | Fastest | Simple splits, arrays | Very simple |
| awk with -F | Very fast | CSV/structured data | Simple |
| tr + loop | Fast | Converting delimiters | Simple |
| Parameter expansion | Fast | Known number of fields | Moderate |
| grep + sed | Medium | Complex patterns | Complex |
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:
| Method | Speed | Memory | Best For |
|---|---|---|---|
| read with IFS | Fastest | Low | Most cases |
| awk | Very Fast | Medium | Complex patterns |
| tr + loop | Medium | Low | Simple 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 arrayfor splitting into array - Use
read -r var1 var2 var3to 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
Recommended Pattern
#!/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