Extract version number from file in shell script

41,734

Solution 1

$ 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))

Solution 2

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

Solution 3

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...

Solution 4

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

Solution 5

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'})

Share:
41,734

Related videos on Youtube

Dougnukem
Author by

Dougnukem

Worked at some game companies and social game startups, working on a new web startup currently. Personal Website

Updated on January 11, 2020

Comments

  • Dougnukem
    Dougnukem over 4 years

    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.

  • Dougnukem
    Dougnukem almost 13 years
    I'm not sure this has anything to do with the problem I asked, maybe I'm misunderstanding what $IFS is and what $version is being set to.
  • geekosaur
    geekosaur almost 13 years
    $IFS is what the shell uses to do its own field ("word") splitting; I am saving the original value (space, tab, newline) and setting it to ., then using set to force $version to be word split. I'll expand on the answer.
  • David W.
    David W. almost 13 years
    mod +1: Very ingenious. IFS is the "Input Field Separator" used by the shell. It is normally set to tab, space, return. geekasaur is changing it to the period. The set -- $version is replacing the command line parameters with the $version field which is split by periods. Thus, the three portions are now $1, $2, $3. If you don't want to use set, you can instead try this: echo $version | read major minor revision. It's not as compact, but doesn't mess with your command line parameters which you still might be using.
  • David W.
    David W. almost 13 years
    But you'd have to repeat the echo | awk three times for each one.
  • geekosaur
    geekosaur almost 13 years
    @David: note that the while loop may run in a subshell, with possibly surprising results (for example, variable settings in the loop won't be seen byt he rest of the script). stackoverflow.com/questions/6245246/…
  • bbaja42
    bbaja42 almost 13 years
    +1, very readable way to skin a cat. Can you explain why it was necessary to write IFS=".$IFS" instead of simply IFS="." ? I've checked IFS="." and it does not work correctly.
  • bbaja42
    bbaja42 almost 13 years
    True. I prefer Cris J answer.
  • Chris J
    Chris J almost 13 years
    Paranoia on my part, as something will fail to work if the default's not there as well :-) My guess is that if IFS doesn't include the newline (by default it's got a space, a tab and a newline), then read doesn't work properly. That said, I've just tried it here, and doing IFS="." works fine here... (bash 3.2.51 running under cygwin).
  • David W.
    David W. almost 13 years
    Man you're fast. I saw the while line in my comments and removed it. It didn't take me more than a minute. Old habit of piping input into a while read loop. Actually, what I put doesn't work in BASH, but does work in Kornshell which is what I use. It's fully compatible with BASH, except when it isn't. In order for this to work in bash, you have to put $version as a here document.
  • Fritz G. Mehner
    Fritz G. Mehner almost 13 years
    4 subshells, 3 pipes, 3 complete processes (at least) just to change one or two characters! That is a little too much.
  • smithfarm
    smithfarm over 11 years
    What geekosaur wrote is exactly what the doctor ordered! I tested David W.'s idea of using echo $version | read major minor revision instead of set -- $version but that didn't work at all.
  • Florian
    Florian over 11 years
    I like this version as it makes no assumption about how many parts the version has. To compose the new version one would have to set IFS and use "${a[*]}", though. Thanks, was able to put it to good use!
  • Huygens
    Huygens over 6 years
    @fgm but at least it works whether you're using bash or not. +1 And you can of course simplify this: echo "$(echo $version | cut -d. -f-2).$(expr $(echo $version | cut -d. -f3) + 1)" it is still a lot of subshells and pipes, but unless you're using a super micro under-powered embedded device that should not matter. If you are after speed, then bash is perhaps not the best choice in the first place ;-)
  • Antônio Medeiros
    Antônio Medeiros over 2 years
    Thank you! In case anyone just needs major.minor, this should give it: echo "1.2.14" | awk -F \. '{version=$1"."$2; print version}' will print out 1.2.