HOWTO · Bash
How to Extract Substring in Bash
This tutorial demonstrates different ways to extract a substring in bash using the cut command, substring expansion and Internal Field Separator.
On this page
To get part of a string in Bash, choose the operation that matches the input: cut selects a delimiter-separated field, Bash substring expansion selects characters by position, and IFS splitting turns delimited text into fields you can handle separately. These methods are related, but they do not return data in the same way.
Extract a Delimited Field with cut
Use cut when the value has a consistent delimiter and you want a particular field. The -d option sets the delimiter, and -f selects a one-based field number. In this example, underscores separate the words, so field 3 is three. Quote the variable expansion and pass it to printf; this keeps the value together as one input line and avoids the unsafe unquoted echo $numbers form.
Run this example:
numbers='one_two_three_four_five'
substring=$(printf '%s\n' "$numbers" | cut -d '_' -f 3)
printf 'substring: %s\n' "$substring"
substring: three
cut selects fields, not an arbitrary range of characters. It is a good fit for structured text whose delimiter and field positions are known; use substring expansion when the desired range is positional instead.
Extract Characters with Bash Substring Expansion
Bash provides substring expansion in the form ${variable:offset:length}. The offset starts at zero, and the length is the number of characters to return. For example, in one_two_three_four_five, offset 4 starts at the t in two, and length 3 selects those three characters. The characters in the original string, including delimiters, count toward the offset.
Run this example:
numbers='one_two_three_four_five'
substring=${numbers:4:3}
printf 'substring: %s\n' "$substring"
substring: two
This is the direct choice when you know a character position and range. The offset is not a field number: if the text before the desired part changes length, the same offset may select different characters. For a value separated into named or numbered fields, cut or IFS is usually easier to adapt.
Split a String into Fields with IFS
IFS is Bash’s Internal Field Separator. It controls word splitting after an unquoted expansion and also affects how the read builtin divides input. A temporary IFS value lets you split a delimited string into positional parameters. $1, $2, and $3 refer to the first, second, and third parameters; they are not array-index syntax.
The example scopes the split to a function and disables pathname expansion before using the unquoted expansion. That matters because word splitting is followed by pathname expansion: if a field contains *, ?, or a bracket pattern, the shell could otherwise replace it with matching filenames. Keep this form for controlled input with a known delimiter. When that delimiter is not whitespace, set IFS to it while reading the input into an array with read -a, then quote array expansions when using the fields. With the default IFS, spaces, tabs, and newlines split fields; changing IFS to a delimiter makes that delimiter split the input. This does not preserve fields that contain the chosen delimiter, and line-oriented read -a cannot preserve embedded line breaks as part of a field. For those formats, use a parser designed for the format rather than relying on read -a alone.
Run this example:
numbers='one_two_three_four_five'
extract_second() (
local IFS=_
set -f
set -- $numbers
printf 'second field: %s\n' "$2"
)
extract_second
second field: two
Within the function, set -- replaces its positional parameters with the split fields; leaving the function restores the caller’s positional parameters. The local separator does not permanently change the script’s IFS.
Choose the Right Method
Choose cut to select a numbered field from text with a known delimiter, such as the third underscore-separated value. Choose Bash substring expansion to take characters at a known zero-based offset and length. Choose IFS splitting when the fields themselves need to become separate shell words or positional parameters for further processing.
For predictable input, each option is compact. Keep cut input quoted, use braces for substring expansion, and remember that unquoted expansion for IFS splitting can also trigger pathname expansion. If the delimiter is part of the data or field contents can include shell pattern characters, use a parsing approach that preserves fields as quoted array elements rather than relying on unquoted word splitting. This distinction helps prevent treating a field number, a character offset, and a positional parameter as interchangeable forms of “substring.”