How to remove last n characters from a string in Bash?


I have a variable var in a Bash script holding a string, like:

echo $var
"some string.rtf"

I want to remove the last 4 characters of this string and assign the result to a new variable var2, so that

echo $var2
"some string"

How can I do this?

2/9/2017 10:28:26 PM

Accepted Answer

First, you should be explicit about what you want. If you know the string ends in .rtf and you want to remove the .rtf, you can use var2=${var%.rtf}. If you don't know what the suffix is but you want to remove everything starting with the last ., then you can use var2=${var%.*}. If you only want to keep everything up to the first ., you can use var2=${var%%.*}. Those last two options have the same result if there's only one period, but if there might be more than one, you get to decide which you want.

If you really want to always remove an exact number of characters, here are some options.

You tagged this bash specifically, so we'll start with bash builtins. The one which has worked the longest is the same suffix-removal syntax I used above: to remove four characters, use var2=${var%????}. You need one question mark per character removed, so this gets unwieldy for larger substring lengths.

Slightly newer is substring extraction: var2=${var::${#var}-4}. Here you can put any number in place of the 4 to remove a different number of characters. (The ${#var} is replaced by the length of the string, so this is actually asking to keep the first (length - 4) characters.)

Newer versions of bash (specifically 4+, which means the one that ships with MacOS won't work) let you simplify that to just var2=${var::-4}.

If you're not actually using bash but some other POSIX-type shell, the suffix removal will still work, even in plain old dash (where none of the rest will). In zsh, they all work but you have to put a 0 between the colons: var2=${var:0:-4} etc. In ksh, you need the 0 and also have to use the explicit length-4 expression: var2=${var:0:${#var}-4}.

You can of course use command substitution to do it with the help of a utility program; there are plenty that will work, but something like var2=$(cut -c -4 <<<"$var") is probably the shortest option.

8/5/2020 10:09:43 PM

To remove four characters from the end of the string use ${var%????}.

To remove everything after the final . use ${var%.*}.


What worked for me was:

echo "hello world" | rev | cut -c5- | rev
# hello w

But I used it to trim lines in a file so that's why it looks awkward. The real use was:

cat somefile | rev | cut -c5- | rev

cut only gets you as far as trimming from some starting position, which is bad if you need variable length rows. So this solution reverses (rev) the string and now we relate to its ending position, then uses cut as mentioned, and reverses (again, rev) it back to its original order.


Using Variable expansion/Substring replacement:


If suffix of var matches Pattern, then substitute Replacement for Pattern.

So you can do:

~$ echo ${var/%????/}
some string


If you have always the same 4 letters

~$ echo ${var/.rtf/}
some string

If it's always ending in .xyz:

~$ echo ${var%.*}
some string

You can also use the length of the string:

~$ len=${#var}
~$ echo ${var::len-4}
some string

or simply echo ${var::-4}


You could use sed,

sed 's/.\{4\}$//' <<< "$var"


$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string

I tried the following and it worked for me:

#! /bin/bash

endindex=$(expr $length - 4)
echo ${var:0:$endindex}

Output: hel