Dougnukem
Dougnukem

Reputation: 14927

Extract version number from file in shell script

I'm trying to write a bash script that increments the version number which is given in

{major}.{minor}.{revision}

For example.

1.2.13

Is there a good way to easily extract those 3 numbers using something like sed or awk such that I could increment the {revision} number and output the full version number string.

Upvotes: 52

Views: 60183

Answers (9)

Noam Manos
Noam Manos

Reputation: 17040

I'm surprised no one suggested grep yet.

Here's how to get the full version (not limited to the length of x.y.z...) from a file name:

filename="openshift-install-linux-4.12.0-ec.3.tar.gz"
find -name "$filename" | grep -Eo '([0-9]+)(\.?[0-9]+)*' | head -1
# 4.12.0

Upvotes: 1

jlliagre
jlliagre

Reputation: 30863

$ v=1.2.13
$ echo "${v%.*}.$((${v##*.}+1))"
1.2.14

$ v=11.1.2.3.0
$ echo "${v%.*}.$((${v##*.}+1))"
11.1.2.3.1

Here is how it works:

The string is split in two parts.

  • the first one contains everything but the last dot and next characters: ${v%.*}
  • the second one contains everything but all characters up to the last dot: ${v##*.}

The first part is printed as is, followed by a plain dot and the last part incremented using shell arithmetic expansion: $((x+1))

Upvotes: 78

Sven Driemecker
Sven Driemecker

Reputation: 3501

Inspired by the answer of jlliagre I made my own version which supports version numbers just having a major version given. jlliagre's version will make 1 -> 1.2 instead of 2.

This one is appropriate to both styles of version numbers:

function increment_version()
    local VERSION="$1"

    local INCREMENTED_VERSION=
    if [[ "$VERSION" =~ .*\..* ]]; then
        INCREMENTED_VERSION="${VERSION%.*}.$((${VERSION##*.}+1))"
    else
        INCREMENTED_VERSION="$((${VERSION##*.}+1))"
    fi

    echo "$INCREMENTED_VERSION"
}

This will produce the following outputs:

increment_version 1         -> 2 
increment_version 1.2       -> 1.3    
increment_version 1.2.9     -> 1.2.10 
increment_version 1.2.9.101 -> 1.2.9.102

Upvotes: 2

Eedoh
Eedoh

Reputation: 6278

I prefer "cut" command for this kind of things

major=`echo $version | cut -d. -f1`
minor=`echo $version | cut -d. -f2`
revision=`echo $version | cut -d. -f3`
revision=`expr $revision + 1`

echo "$major.$minor.$revision"

I know this is not the shortest way, but for me it's simplest to understand and to read...

Upvotes: 52

tylo
tylo

Reputation: 1

Small variation on fgm's solution using the builtin read command to split the string into an array. Note that the scope of the IFS variable is limited to the read command (so no need to store & restore the current IFS variable).

version='1.2.33'
IFS='.' read -r -a a <<<"$version"
((a[2]++))
printf '%s\n' "${a[@]}" | nl
version="${a[0]}.${a[1]}.${a[2]}"
echo "$version"

See: How do I split a string on a delimiter in Bash?

Upvotes: 0

Fritz G. Mehner
Fritz G. Mehner

Reputation: 17198

Pure Bash using an array:

version='1.2.33'
a=( ${version//./ } )                   # replace points, split into array
((a[2]++))                              # increment revision (or other part)
version="${a[0]}.${a[1]}.${a[2]}"       # compose new version

Upvotes: 54

Callie J
Callie J

Reputation: 31326

Yet another shell way (showing there's always more than one way to bugger around with this stuff...):

$ echo 1.2.3 | ( IFS=".$IFS" ; read a b c && echo $a.$b.$((c + 1)) )
1.2.4

So, we can do:

$ x=1.2.3
$ y=`echo $x | ( IFS=".$IFS" ; read a b c && echo $a.$b.$((c + 1)) )`
$ echo $y
1.2.4

Upvotes: 15

bbaja42
bbaja42

Reputation: 2169

Awk makes it quite simple:

echo "1.2.14" | awk -F \. {'print $1,$2, $3'} will print out 1 2 14.

flag -F specifies separator.

If you wish to save one of the values:

firstVariable=$(echo "1.2.14" | awk -F \. {'print $1'})

Upvotes: 9

geekosaur
geekosaur

Reputation: 61457

I use the shell's own word splitting; something like

oIFS="$IFS"
IFS=.
set -- $version
IFS="$oIFS"

although you need to be careful with version numbers in general due to alphabetic or date suffixes and other annoyingly inconsistent bits. After this, the positional parameters will be set to the components of $version:

$1 = 1
$2 = 2
$3 = 13

($IFS is a set of single characters, not a string, so this won't work with a multicharacter field separator, although you can use IFS=.- to split on either . or -.)

Upvotes: 7

Related Questions