How can I increment a number at the end of a string in bash?
updateVersion()
{
[[ $1 =~ ([^0-9]*)([0-9]+) ]] || { echo 'invalid input'; exit; }
echo "${BASH_REMATCH[1]}$(( ${BASH_REMATCH[2]} + 1 ))"
}
# Usage
updateVersion version_11 # output: version_12
updateVersion version11 # output: version12
updateVersion something_else123 # output: something_else124
updateVersion "with spaces 99" # output: with spaces 100
# Putting it in a variable
v2="$(updateVersion version2)"
echo "$v2" # output: version3
Late to the party here, but there is an issue with the accepted answer. It works for the OP's case where there are no numbers before the end, but I had an example like this:
1.0.143
For that, the regexp needs to be a bit looser. Here's how I did it, preserving leading zeroes:
#!/usr/bin/env bash
updateVersion()
{
[[ ${1} =~ ^(.*[^0-9])?([0-9]+)$ ]] && \
[[ ${#BASH_REMATCH[1]} -gt 0 ]] && \
printf "%s%0${#BASH_REMATCH[2]}d" "${BASH_REMATCH[1]}" "$((10#${BASH_REMATCH[2]} + 1 ))" || \
printf "%0${#BASH_REMATCH[2]}d" "$((10#${BASH_REMATCH[2]} + 1))" || \
printf "${1}"
}
# Usage
updateVersion 09 # output 10
updateVersion 1.0.450 # output 1.0.451
updateVersion version_01 # output version_02
updateVersion version12 # output version13
updateVersion version19 # output version20
Notes:
- You only need to double-quote the first argument to
printf
. - Replace
${1}
with content in""
if you want to use it on a command line, instead of in a function. - You can switch the last
printf
to a basicecho
if you prefer. If you are just printing tostdout
orstderr
, consider adding a newline (\n
) at the end of eachprintf
. - You can combine the function content into a single line, but it's harder to read. It's better to break it into lines with
\
at every if (&&
) and else (||
), as above.
What the function does - line by line:
- Test the passed value ends with a number of one or more digits, optionally prefixed by at least one non-number. Split into two groups accordingly (indexing is 1-based).
- When ending in a number, test there is a non-numeric prefix (i.e. length of group 1 > 0).
- When there are non-numerics, print group 1 (a string) followed by group 2 (an integer padded with zeroes to match the original string size). Group 2 is base-10 converted and incremented by 1. The conversion is important - leading zeroes are interpreted as octal by default.
- When there are only numbers, increment as above but just print group 2.
- If the input is anything else, return the supplied string.
incrementTrailingNumber() {
local prefix number
if [[ $1 =~ ^(.*[^[:digit:]])([[:digit:]]+)$ ]]; then
prefix=${BASH_REMATCH[1]}
number=${BASH_REMATCH[2]}
printf '%s%s\n' "$prefix" "$(( number + 1 ))"
else
printf '%s\n' "$1"
fi
}
Usage as:
$ incrementTrailingNumber version_30
version_31
$ incrementTrailingNumber foo-2.15
foo-2.16
$ incrementTrailingNumber noNumberHereAtAll # demonstrate noop case
noNumberHereAtAll