The following simple version control script is meant to find the last version number of a given file, increment it, run a given command with the newly created file (e.g., ed
For just incrementing the dewey decimal version:
awk -F. -v OFS=. '{$NF++;print}'
Or in a shell script:
NEXTVERSION=$(echo ${VERSION} | awk -F. -v OFS=. '{$NF++;print}')
Pure Bash:
increment_version ()
{
declare -a part=( ${1//\./ } )
declare new
declare -i carry=1
for (( CNTR=${#part[@]}-1; CNTR>=0; CNTR-=1 )); do
len=${#part[CNTR]}
new=$((part[CNTR]+carry))
[ ${#new} -gt $len ] && carry=1 || carry=0
[ $CNTR -gt 0 ] && part[CNTR]=${new: -len} || part[CNTR]=${new}
done
new="${part[*]}"
echo -e "${new// /.}"
}
version='1.2.3.44'
increment_version $version
result:
1.2.3.45
The version string is split and stored in the array part. The loop goes from the last to the first part of the version. The last part will be incremented and possibly cut down to its original length. A carry is taken to the next part.
Usage
increment_version 1.39.0 0 # 2.39.0
increment_version 1.39.0 1 # 1.40.0
increment_version 1.39.0 2 # 1.39.1
### Increments the part of the string
## $1: version itself
## $2: number of part: 0 – major, 1 – minor, 2 – patch
increment_version() {
local delimiter=.
local array=($(echo "$1" | tr $delimiter '\n'))
array[$2]=$((array[$2]+1))
echo $(local IFS=$delimiter ; echo "${array[*]}")
}
Simplified version of @dimpiax answer
EDIT: I created another version of this script that put zeros on the less important parts if the most important ones are changed. Just note the diferent expected results on the usage part.
Usage
increment_version 1.39.3 0 # 2.0.0
increment_version 1.39.3 1 # 1.40.0
increment_version 1.39.3 2 # 1.39.4
#!/bin/bash
### Increments the part of the string
## $1: version itself
## $2: number of part: 0 – major, 1 – minor, 2 – patch
increment_version() {
local delimiter=.
local array=($(echo "$1" | tr $delimiter '\n'))
array[$2]=$((array[$2]+1))
if [ $2 -lt 2 ]; then array[2]=0; fi
if [ $2 -lt 1 ]; then array[1]=0; fi
echo $(local IFS=$delimiter ; echo "${array[*]}")
}
Determining a version number for a software project is based on its relative change / functionality / development stage / revision. Consequent increments to the version and revision numbering is ideally a process that should be done by a human. However, not to second-guess your motivation for writing this script, here is my suggestion.
Include some logic in your script that will do exactly what you describe in your requirement
"...if the last section after dot has two digits, inc until 99; if only 1, then inc until 9 ... "
Assuming the third position is the development stage number $dNum
and the fourth (last) position is the revision number $rNum
:
if [ $(expr length $rNum) = "2" ] ; then
if [ $rNum -lt 99 ]; then
rNum=$(($rNum + 1))
else rNum=0
dNum=$(($dNum + 1)) #some additional logic for $dNum > 9 also needed
fi
elif [ $(expr length $dNum) = "1" ] ; then
...
...
fi
Perhaps a function will allow the most succinct way of handling all positions (majNum.minNum.dNum.rNum).
You will have to separate the project name and version number components of your filename in your script and then construct the version number with all its positions, and finally reconstruct the filename with something like
new_version="$majNum.minNum.$dNum.$rNum"
new_version_file="$old_file.$new_version"
Hope that helps and check this SO discussion as well as this wikipedia entry if you want to know more about versioning conventions.
increment_version 1.39.0 0 # 2.39.0
increment_version 1.39.0 1 # 1.40.0
increment_version 1.39.0 2 # 1.39.1
### Increments the part of the string
## $1: version itself
## $2: number of part: 0 – major, 1 – minor, 2 – patch
increment_version() {
local delimiter=.
local array=($(echo "$1" | tr $delimiter '\n'))
for index in ${!array[@]}; do
if [ $index -eq $2 ]; then
local value=array[$index]
value=$((value+1))
array[$index]=$value
break
fi
done
echo $(IFS=$delimiter ; echo "${array[*]}")
}
Here is an even shorter version that also supports a postfix (nice for -SNAPSHOT)
$ cat versions
1.2.3.44
1.2.3.9
1.2.3
9
42.2-includes-postfix
$ perl -pe 's/^((\d+\.)*)(\d+)(.*)$/$1.($3+1).$4/e' < versions
1.2.3.45
1.2.3.10
1.2.4
10
42.3-includes-postfix
I used regex to capture 3 parts. The stuff before the last position, the number to increment, and the stuff after.
((\d+\.)*)
- stuff of the from 1.1.1.1.1.(\d+)
- the last digit(.*)
- the stuff after the last digitI then use the e option to allow expressions in the replace part. Note with the e option \1 becomes a variable $1 and you need to concatenate variables with the dot operator.
$1
- the capture group of 1.1.1.1.1.($3+1)
- increment the last digit. note $2 is used in the sub group of $1 to get the repeated 1.$4
- the stuff after the last digit