Bash String Manipulation: Substring, Replace, Length, and More

By 

Published on

4 min read

Bash string manipulation with parameter expansion

When you write Bash scripts, many small text tasks do not need sed, awk, or another external command. Parameter expansion can extract part of a string, replace text, strip a prefix, or change case directly inside ${}.

This guide covers the most useful string operations with practical examples for each one.

String Length

Get the number of characters in a variable using ${#variable}:

Terminal
filename="backup-2026-04-14.tar.gz"
echo "${#filename}"
output
24

This returns the character count. For strings that contain only ASCII characters, the character count and byte count are the same.

Extracting a Substring

Use ${variable:offset:length} to extract part of a string:

Terminal
str="Hello, World"
echo "${str:7:5}"
output
World

The offset is zero-based, so 7 starts at the eighth character. 5 is how many characters to return.

Omit the length to extract from the offset to the end of the string:

Terminal
echo "${str:7}"
output
World

Negative offsets count from the end of the string. Note the space before the minus sign; it is required to avoid being interpreted as the :- default value syntax:

Terminal
echo "${str: -5}"
output
World

Replacing a Substring

Use ${variable/pattern/replacement} to replace the first match of a pattern:

Terminal
path="/var/log/app/error.log"
echo "${path/log/logs}"
output
/var/logs/app/error.log

Only the first occurrence is replaced. To replace every occurrence, double the forward slash:

Terminal
echo "${path//log/logs}"
output
/var/logs/app/error.logs

Leave the replacement empty to delete a substring:

Terminal
version="v1.2.3"
echo "${version/v/}"
output
1.2.3

The pattern supports glob characters: * matches any sequence of characters, ? matches a single character, and [...] matches a character class.

Removing a Prefix

Use # to remove a prefix from the beginning of a string. The shortest matching prefix is removed:

Terminal
file="photo.backup.tar.gz"
echo "${file#*.}"
output
backup.tar.gz

Use ## to remove the longest possible matching prefix:

Terminal
echo "${file##*.}"
output
gz

A common use is stripping a directory path to get just the filename:

Terminal
filepath="/home/user/documents/report.pdf"
echo "${filepath##*/}"
output
report.pdf

Removing a Suffix

Use % to strip a suffix from the end of a string. The shortest match is removed:

Terminal
file="photo.backup.tar.gz"
echo "${file%.*}"
output
photo.backup.tar

Use %% for the longest match:

Terminal
echo "${file%%.*}"
output
photo

Combining prefix and suffix removal is a clean way to extract a bare filename from a path:

Terminal
filepath="/home/user/documents/report.pdf"
base="${filepath##*/}"
name="${base%.*}"
echo "$name"
output
report

Changing Case

Convert a string to uppercase with ^^:

Terminal
greeting="hello, world"
echo "${greeting^^}"
output
HELLO, WORLD

Convert to lowercase with ,,:

Terminal
input="Hello World"
echo "${input,,}"
output
hello world

To capitalize only the first character, use a single ^:

Terminal
word="linux"
echo "${word^}"
output
Linux

To lowercase only the first character, use a single ,:

Terminal
word="LINUX"
echo "${word,}"
output
lINUX

Case conversion requires Bash 4.0 or newer. The default shell on older macOS systems ships with Bash 3.2 and does not support these operators. As a portable alternative, use tr:

Terminal
echo "$greeting" | tr '[:lower:]' '[:upper:]'

Checking if a String Contains a Substring

Use a glob pattern inside [[ ]] to test whether a string contains another string:

Terminal
str="Running on Linux kernel 6.8"
if [[ "$str" == *"Linux"* ]]; then
    echo "Linux detected"
fi
output
Linux detected

The * wildcards match anything before and after the search pattern. The comparison is case-sensitive. To check case-insensitively, convert both sides to the same case first using ,, before comparing.

For a more detailed walkthrough of substring detection, including case-insensitive matching and edge cases, see How to Check if a String Contains a Substring in Bash . For more on [[ ]] conditionals and string comparison operators, see the guide on Bash comparison operators .

Quick Reference

For a printable quick reference, see the Bash cheatsheet .

OperationSyntax
String length${#var}
Substring from offset${var:offset}
Substring with length${var:offset:length}
Replace first match${var/pattern/replacement}
Replace all matches${var//pattern/replacement}
Delete substring${var/pattern/}
Remove shortest prefix${var#pattern}
Remove longest prefix${var##pattern}
Remove shortest suffix${var%pattern}
Remove longest suffix${var%%pattern}
Uppercase all${var^^}
Lowercase all${var,,}
Uppercase first char${var^}
Lowercase first char${var,}

Conclusion

Bash parameter expansion handles most day-to-day string operations without extra commands, which keeps scripts shorter and faster. For more on working with strings, see the guides on Bash string concatenation and splitting strings by delimiter .

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

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