Bash Split String: Split a String by Delimiter

When a script reads a CSV row, a colon-separated config line, or a piece of user input, one of the first things you usually need to do is break that string into its individual fields. Bash does not have a dedicated split function, but the shell gives you several ways to do the job with nothing more than built-ins and common core utilities.
This guide explains how to split a string by a delimiter in Bash using read, the IFS variable, tr, awk, and parameter expansion, with safe examples you can drop straight into a script.
The IFS Variable
Word splitting in Bash is controlled by the internal field separator, stored in the IFS variable. By default, IFS contains a space, a tab, and a newline, which is why unquoted expansions split on whitespace. When you set IFS to a single character such as a comma or a colon, Bash uses that character to decide where one field ends and the next begins.
Most of the techniques below work by changing IFS for one command only, so the rest of the script keeps the default behavior.
Splitting a String with read
The cleanest way to split a string into named variables is the read built-in combined with a temporary IFS:
#!/bin/bash
STR="ubuntu:debian:fedora:arch"
IFS=":" read -r first second third fourth <<< "$STR"
echo "$first"
echo "$second"
echo "$third"
echo "$fourth"Running the script produces one field per line:
ubuntu
debian
fedora
archThe IFS=":" assignment applies only to the read command that follows it, so the global IFS stays untouched. The here-string (<<<) feeds the string into read on standard input, and -r keeps backslashes literal so they are not treated as escape characters.
Splitting Into a Bash Array
When the number of fields is not known ahead of time, split the string into an array instead of a fixed list of variables. Pass -a to read to tell it the target is an array:
#!/bin/bash
STR="1,2,3,4,5"
IFS="," read -r -a numbers <<< "$STR"
for n in "${numbers[@]}"; do
echo "$n"
doneThe numbers array now holds one value per comma-separated field, and the loop prints each one on its own line. Always expand arrays with "${numbers[@]}" inside double quotes so elements that contain spaces stay intact.
For a deeper look at what else arrays can do, see our guide on Bash arrays .
Splitting With a Multi-Character Delimiter
IFS treats each character in its value as a separate delimiter, so setting IFS="::" will still split on single colons. For a multi-character delimiter such as :: or -, convert it to a single character first with sed or use parameter expansion:
#!/bin/bash
STR="alpha::beta::gamma"
IFS="|" read -r -a parts <<< "${STR//::/|}"
for p in "${parts[@]}"; do
echo "$p"
doneThe ${STR//::/|} expansion replaces every occurrence of :: with a pipe character, and then read splits the resulting string on the pipe. Pick a placeholder character that you are sure the input does not contain.
Splitting With tr
When you only need the fields printed one per line, tr is often enough. It translates the delimiter into a newline:
printf '%s\n' "red,green,blue" | tr ',' '\n'red
green
blueThis approach pairs well with pipelines. For example, you can count the number of fields by piping the output into wc -l, or loop over the values with a while read block:
#!/bin/bash
STR="red,green,blue"
while IFS= read -r color; do
echo "Color: $color"
done < <(printf '%s\n' "$STR" | tr ',' '\n')The process substitution <(...) sends the output of the pipeline into the loop without using a subshell for the loop body, so any variables you set inside the loop remain available after it ends.
Splitting With awk
For more structured splitting, awk is the right tool. It reads input one record at a time and exposes each field as $1, $2, and so on. Use -F to set the field separator:
echo "jane:x:1001:1001:Jane Doe:/home/jane:/bin/bash" | awk -F':' '{ print $1, $5 }'jane Jane Doeawk is also a good pick when the delimiter is a regular expression, when you need to skip a header line, or when you want to act on a specific field without touching the rest. For more patterns, see our awk command guide
.
Splitting With Parameter Expansion
Bash parameter expansion can pull a prefix or a suffix off a string without calling any external command. This is the fastest option when you only need one part, not all of them:
#!/bin/bash
PATH_LINE="/usr/local/bin/script.sh"
BASE="${PATH_LINE##*/}"
DIR="${PATH_LINE%/*}"
echo "Directory: $DIR"
echo "Basename: $BASE"Directory: /usr/local/bin
Basename: script.sh##*/ strips the longest match of */ from the start of the string, leaving the basename. %/* strips the shortest match of /* from the end, leaving the directory. The same pattern works for any delimiter, not only the slash.
For full coverage of these expansions, see our guide on Bash string manipulation .
Preserving Empty Fields
A common surprise with read is that trailing empty fields can be dropped. Consider the string a,,b,:
#!/bin/bash
STR="a,,b,"
IFS="," read -r -a fields <<< "${STR},"
echo "Count: ${#fields[@]}"
printf '[%s]\n' "${fields[@]}"Count: 4
[a]
[]
[b]
[]Bash keeps empty fields in the middle, but read -a drops a trailing empty field when the delimiter is the last character. Appending one extra delimiter before reading gives read a final empty value to assign, which preserves the trailing field from the original string.
Quick Reference
The table below summarizes which technique to reach for based on what the script needs to do.
| Goal | Technique |
|---|---|
| Split into named variables | IFS=":" read -r a b c <<< "$STR" |
| Split into an array | IFS="," read -r -a arr <<< "$STR" |
| Multi-character delimiter | Replace with ${STR//::/|} first, then split |
| Print one field per line | printf '%s\n' "$STR" | tr ',' '\n' |
| Select specific fields | awk -F',' '{ print $2 }' |
| Take prefix or suffix only | ${STR%%...} / ${STR##...} |
For a printable quick reference, see the bash cheatsheet .
FAQ
How do I split a string by whitespace in Bash?
Leave IFS at its default and use read -r -a arr <<< "$STR". Any run of spaces, tabs, or newlines will act as a separator.
Why does my array lose the last empty field?
If the delimiter is at the very end of the string, read -a can drop the trailing empty element. Append one extra delimiter before reading, for example IFS=',' read -r -a arr <<< "${STR},", when the trailing empty field matters.
Can I split on a newline?
Yes. For line-based strings, use mapfile -t lines <<< "$STR" so each input line becomes one array element. Plain read stops at the first newline unless you change how it reads the input.
Is there a built-in split function in Bash?
No. Word splitting driven by IFS plus the read built-in is the idiomatic replacement for a dedicated split function.
Conclusion
Splitting strings in Bash comes down to picking the right tool for the shape of the input: read with IFS for structured parsing, tr or awk for pipelines, and parameter expansion for quick prefix or suffix work. When the input is untrusted, quote every expansion and handle empty fields on purpose rather than by accident.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page