How to increment version number in a shell script?

前端 未结 11 2035
执念已碎
执念已碎 2020-11-29 23:47

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

相关标签:
11条回答
  • 2020-11-30 00:31

    Another option is to use Python. I think this way it a bit more readable than using plain Bash or Perl.

    function increase_version() {
        python - "$1" <<EOF
    import sys
    version = sys.argv[1]
    base, _, minor = version.rpartition('.')
    print(base + '.' + str(int(minor) + 1))
    EOF
    }
    
    0 讨论(0)
  • 2020-11-30 00:34

    Tired of bash? Why not try Perl?

    $ cat versions
    1.2.3.44
    1.2.3.9
    1.2.3
    9
    
    $ cat versions | perl -ne 'chomp; print join(".", splice(@{[split/\./,$_]}, 0, -1), map {++$_} pop @{[split/\./,$_]}), "\n";'
    1.2.3.45
    1.2.3.10
    1.2.4
    10
    

    Not quite in compliance with the requirement, of course.

    0 讨论(0)
  • 2020-11-30 00:38
    $ echo 1.2.3.4 | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF+1)%(10^length($NF))); print}'
    1.2.3.5
    

    1.2.3.9  => 1.2.4.0
    1.2.3.44 => 1.2.3.45
    1.2.3.99 => 1.2.4.00
    1.2.3.999=> 1.2.4.000
    1.2.9    => 1.3.0
    999      => 1000
    

    UPDATE:

    #!/usr/bin/gawk -f
    
    BEGIN{
        v[1] = "1.2.3.4"
        v[2] = "1.2.3.44"
        v[3] = "1.2.3.99"
        v[4] = "1.2.3"
        v[5] = "9"
        v[6] = "9.9.9.9"
        v[7] = "99.99.99.99"
        v[8] = "99.0.99.99"
        v[9] = ""
    
        for(i in v)
            printf("#%d: %s => %s\n", i, v[i], inc(v[i])) | "sort | column -t"
    }
    
    function inc(s,    a, len1, len2, len3, head, tail)
    {
        split(s, a, ".")
    
        len1 = length(a)
        if(len1==0)
            return -1
        else if(len1==1)
            return s+1
    
        len2 = length(a[len1])
        len3 = length(a[len1]+1)
    
        head = join(a, 1, len1-1)
        tail = sprintf("%0*d", len2, (a[len1]+1)%(10^len2))
    
        if(len2==len3)
            return head "." tail
        else
            return inc(head) "." tail
    }
    
    function join(a, x, y,    s)
    {
        for(i=x; i<y; i++)
            s = s a[i] "."
        return s a[y]
    }
    

    $ chmod +x inc.awk
    $ ./inc.awk
    #1:  1.2.3.4      =>  1.2.3.5
    #2:  1.2.3.44     =>  1.2.3.45
    #3:  1.2.3.99     =>  1.2.4.00
    #4:  1.2.3        =>  1.2.4
    #5:  9            =>  10
    #6:  9.9.9.9      =>  10.0.0.0
    #7:  99.99.99.99  =>  100.00.00.00
    #8:  99.0.99.99   =>  99.1.00.00
    #9:  =>           -1
    
    0 讨论(0)
  • 2020-11-30 00:38

    Here are a couple more flexible options. Both accept a second argument to indicate which position to increment.

    1. Simple function

    For more predictable input.

    # Usage: increment_version <version> [<position>]
    increment_version() {
     local v=$1
     if [ -z $2 ]; then 
        local rgx='^((?:[0-9]+\.)*)([0-9]+)($)'
     else 
        local rgx='^((?:[0-9]+\.){'$(($2-1))'})([0-9]+)(\.|$)'
        for (( p=`grep -o "\."<<<".$v"|wc -l`; p<$2; p++)); do 
           v+=.0; done; fi
     val=`echo -e "$v" | perl -pe 's/^.*'$rgx'.*$/$2/'`
     echo "$v" | perl -pe s/$rgx.*$'/${1}'`printf %0${#val}s $(($val+1))`/
    }
    
    # EXAMPLE   ------------->   # RESULT
    increment_version 1          # 2
    increment_version 1.0.0      # 1.0.1
    increment_version 1 2        # 1.1
    increment_version 1.1.1 2    # 1.2
    increment_version 00.00.001  # 00.00.002
    

    2. Robust function

    For use with scripts, or more customizability to apply to various versioning systems. It could use a couple more options, but as it stands now it works for my projects using the "major.minor[.maintenance[.build]]" version sequences.

    # Accepts a version string and prints it incremented by one.
    # Usage: increment_version <version> [<position>] [<leftmost>]
    increment_version() {
       local usage=" USAGE: $FUNCNAME [-l] [-t] <version> [<position>] [<leftmost>]
               -l : remove leading zeros
               -t : drop trailing zeros
        <version> : The version string.
       <position> : Optional. The position (starting with one) of the number 
                    within <version> to increment.  If the position does not 
                    exist, it will be created.  Defaults to last position.
       <leftmost> : The leftmost position that can be incremented.  If does not
                    exist, position will be created.  This right-padding will
                    occur even to right of <position>, unless passed the -t flag."
    
       # Get flags.
       local flag_remove_leading_zeros=0
       local flag_drop_trailing_zeros=0
       while [ "${1:0:1}" == "-" ]; do
          if [ "$1" == "--" ]; then shift; break
          elif [ "$1" == "-l" ]; then flag_remove_leading_zeros=1
          elif [ "$1" == "-t" ]; then flag_drop_trailing_zeros=1
          else echo -e "Invalid flag: ${1}\n$usage"; return 1; fi
          shift; done
    
       # Get arguments.
       if [ ${#@} -lt 1 ]; then echo "$usage"; return 1; fi
       local v="${1}"             # version string
       local targetPos=${2-last}  # target position
       local minPos=${3-${2-0}}   # minimum position
    
       # Split version string into array using its periods. 
       local IFSbak; IFSbak=IFS; IFS='.' # IFS restored at end of func to                     
       read -ra v <<< "$v"               #  avoid breaking other scripts.
    
       # Determine target position.
       if [ "${targetPos}" == "last" ]; then 
          if [ "${minPos}" == "last" ]; then minPos=0; fi
          targetPos=$((${#v[@]}>${minPos}?${#v[@]}:$minPos)); fi
       if [[ ! ${targetPos} -gt 0 ]]; then
          echo -e "Invalid position: '$targetPos'\n$usage"; return 1; fi
       (( targetPos--  )) || true # offset to match array index
    
       # Make sure minPosition exists.
       while [ ${#v[@]} -lt ${minPos} ]; do v+=("0"); done;
    
       # Increment target position.
       v[$targetPos]=`printf %0${#v[$targetPos]}d $((10#${v[$targetPos]}+1))`;
    
       # Remove leading zeros, if -l flag passed.
       if [ $flag_remove_leading_zeros == 1 ]; then
          for (( pos=0; $pos<${#v[@]}; pos++ )); do
             v[$pos]=$((${v[$pos]}*1)); done; fi
    
       # If targetPosition was not at end of array, reset following positions to
       #   zero (or remove them if -t flag was passed).
       if [[ ${flag_drop_trailing_zeros} -eq "1" ]]; then
            for (( p=$((${#v[@]}-1)); $p>$targetPos; p-- )); do unset v[$p]; done
       else for (( p=$((${#v[@]}-1)); $p>$targetPos; p-- )); do v[$p]=0; done; fi
    
       echo "${v[*]}"
       IFS=IFSbak
       return 0
    }
    
    # EXAMPLE   ------------->   # RESULT
    increment_version 1          # 2
    increment_version 1 2        # 1.1
    increment_version 1 3        # 1.0.1
    increment_version 1.0.0      # 1.0.1
    increment_version 1.2.3.9    # 1.2.3.10
    increment_version 00.00.001  # 00.00.002
    increment_version -l 00.001  # 0.2
    increment_version 1.1.1.1 2   # 1.2.0.0
    increment_version -t 1.1.1 2  # 1.2
    increment_version v1.1.3      # v1.1.4
    increment_version 1.2.9 2 4     # 1.3.0.0
    increment_version -t 1.2.9 2 4  # 1.3
    increment_version 1.2.9 last 4  # 1.2.9.1
    

    Obviously, this is excessive just to increment a version string. But I wrote this because I had a need for different types of projects, and because if speed is not an issue, I prefer reusability over tweaking the same code across dozens of scripts. I guess that's just my object-oriented side leaking into my scripts.

    0 讨论(0)
  • 2020-11-30 00:38

    Using just bash, wc and sed:

    #! /bin/bash
    for v in 1.2.3.44 1.2.3.9 1.2.3 9 1.4.29.9 9.99.9 ; do
        echo -n $v '-> '
    
        num=${v//./}
        let num++
    
        re=${v//./)(}
        re=${re//[0-9]/.}')'
        re=${re#*)}
    
        count=${v//[0-9]/}
        count=$(wc -c<<<$count)
        out=''
        for ((i=count-1;i>0;i--)) ; do
            out='.\'$i$out
        done
    
        sed -r s/$re$/$out/ <<<$num
    done
    
    0 讨论(0)
提交回复
热议问题