Bash Split String: 4 Methods & Examples
To split a string in Bash, you can use the Internal Field Separator (IFS), the read command, the mapfile command, or parameter expansion. The method you choose depends on whether you need to split by a single character, a delimiter string, or a fixed number of fields. This article explains each approach with concrete examples and discusses common pitfalls.
Background: Why Splitting Strings in Bash Is Tricky
Unlike higher-level languages like Python or JavaScript, Bash does not have a built-in split() function. Instead, it relies on word splitting, which is controlled by the IFS variable. This can be confusing because the behavior changes depending on whether you are in an interactive shell, a script, or a command substitution. Understanding how IFS works is the key to splitting strings reliably.
Method 1: Using IFS and the read Command
The most common way to split a string into an array is to set IFS to the delimiter and use read -a (or read -r -a for backslash-safe reading). Here is an example:
string="apple,banana,cherry"
IFS=',' read -r -a array <<< "$string"
echo "${array[0]}" # apple
echo "${array[1]}" # banana
echo "${array[2]}" # cherry
This works by temporarily setting IFS to a comma, then using a here-string (<<<) to feed the string to read. The -r flag prevents backslash escapes from being interpreted, which is usually what you want. Note that this method splits on any single character in IFS, not on a multi-character delimiter. If you need to split on a string like "||", this method will not work.
Method 2: Using mapfile (Bash 4+)
The mapfile (or readarray) command reads lines from standard input into an array. You can combine it with a process substitution or a here-string to split on a delimiter. For example:
string="one two three"
mapfile -t array <<< "$string"
echo "${array[1]}" # two
This splits on newlines by default. To split on a different delimiter, you can use tr to replace the delimiter with a newline:
string="apple,banana,cherry"
mapfile -t array < <(tr ',' '\n' <<< "$string")
echo "${array[0]}" # apple
This approach is useful when you want to read lines from a file or command output. However, it is less efficient than the read method for simple splits.
Method 3: Using Parameter Expansion
Bash parameter expansion can split a string into positional parameters. This is useful when you know the number of fields in advance. For example:
string="user:password:uid:gid"
IFS=':' read -r user pass uid gid <<< "$string"
echo "$user" # user
Here, the string is split into four variables. If there are more fields than variables, the last variable gets the remainder. If there are fewer, the extra variables are empty. This method is handy for parsing structured data like /etc/passwd lines.
Method 4: Using the for Loop with Word Splitting
You can also split a string by relying on Bash's word splitting in a for loop. This is the simplest approach when you just need to iterate over the parts:
string="apple banana cherry"
for word in $string; do
echo "$word"
done
This splits on whitespace (spaces, tabs, newlines) because IFS defaults to that. To split on a custom delimiter, set IFS temporarily:
string="apple,banana,cherry"
IFS=',' read -ra parts <<< "$string"
for part in "${parts[@]}"; do
echo "$part"
done
Be careful: if the string contains glob characters like * or ?, word splitting may also perform pathname expansion, which can lead to unexpected results. Use set -f to disable globbing if needed.
How to Choose the Right Method
- Split into an array – use
IFSwithread -a. - Split into named variables – use
IFSwithreadand multiple variable names. - Split on a multi-character delimiter – use
sed,awk, or parameter expansion with${var//pattern/replacement}. - Split lines from a file – use
mapfile. - Iterate over parts – use a
forloop with word splitting (but disable globbing).
Common Mistakes and Pitfalls
- Forgetting to quote the string – if you use
read -awithout a here-string, the shell may split the input again. - Not resetting IFS – changing
IFSin a script can affect later commands. Always save and restore it, or use a subshell. - Trailing empty fields –
read -adrops trailing empty fields. For example,"a,b,"becomes(a b)instead of(a b ''). - Whitespace in the delimiter – if your delimiter is a space, the default
IFSwill treat consecutive spaces as one separator. To split on every space, setIFS=' 'but be aware that leading/trailing spaces are ignored. - Using
echowith arrays –echo "${array}"only prints the first element. Use"${array[@]}"to print all.
Alternatives: awk, cut, and sed
If you are already using external tools, cut, awk, and sed can split strings with more flexibility. For example, to get the second field of a comma-separated string:
echo "apple,banana,cherry" | cut -d',' -f2 # banana
Or with awk:
echo "apple,banana,cherry" | awk -F',' '{print $2}' # banana
These tools are especially useful for splitting on multi-character delimiters or when you need to process large amounts of text. However, they spawn a subprocess, so they are slower than pure Bash methods for simple tasks.
Frequently Asked Questions
How do I split a string by a delimiter in Bash?
Use the IFS variable with the read command: IFS=',' read -ra parts <<< "$string". This splits the string into an array named parts.
How do I split a string into an array in Bash?
Use read -a with a custom IFS, or mapfile if you are splitting on newlines. For example: IFS=' ' read -ra arr <<< "$str".
How do I split a string by a multi-character delimiter in Bash?
Bash's IFS only supports single-character delimiters. For multi-character delimiters, use awk with -F'||', or use parameter expansion: ${var//delimiter/ } and then split on spaces.
Why does my Bash split ignore empty fields?
The read command (and word splitting) collapses consecutive delimiters and drops leading/trailing empty fields. To preserve them, use a different tool like awk with -F and NF, or use sed to replace the delimiter with a newline and then read lines.
Can I split a string in Bash without using IFS?
Yes, you can use mapfile with tr to replace the delimiter with a newline, or use parameter expansion like ${var//:/ } to replace the delimiter with spaces and then use read -a with the default IFS.
How do I split a string into variables in Bash?
Use IFS=',' read -r var1 var2 var3 <<< "$string". The string will be split into the given variable names. If there are more fields than variables, the last variable contains the rest.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.