Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
805 views
in Technique[技术] by (71.8m points)

bash - How to increment version number in a shell script?

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., editor), and after that save it to stable. Since it's simple, it doesn't check anything since the script would be modified as needed. For instance, if the result won't be stable, the user can omit the last argument.

However, one major concern of the current functionality is how to implement the following: if the last section after dot has two digits, inc untill 99; if only 1, then inc until 9, then move to the previous section. The versions may have any positive integer number of sections.

1.2.3.44 -> 1.2.3.45
1.2.3.9 -> 1.2.4.0
1.2.3 -> 1.2.4
9 -> 10

The remaining issue is that it doesn't wait for a tabbed wine editor to close the file; the goal is to detect when the tab is closed. Also, could you explain how best to make sure that my variable names don't overwrite existing ones?

You can also offer other improvements.

#!/bin/bash
#Tested on bash 4.1.5
#All arguments in order: "folder with file" "file pattern" cmd [stable name]
folder="$1"
file_pattern="$2"
cmd="$3"
stable="$4"

cd "$folder"
last_version=$(ls --format=single-column --almost-all | 
    grep "$file_pattern" | 
    sed -nr 's/^[^0-9]*(([0-9]+.)*[0-9]+).*/1/p' | 
    sort -Vu | 
    tail -n 1)
last_version_file=$(ls --format=single-column --almost-all | 
    grep "$file_pattern" | 
    grep $last_version | 
    tail -n 1) #tail -n 1 is only needed to get 1 line if there are backup files with the same version number
new_version=$(echo $last_version | 
    gawk -F"." '{$NF+=1}{print $0RT}' OFS="." ORS="") #increments last section indefinitely
new_version_file=$(echo "$last_version_file" | 
    sed -r "s/$last_version/$new_version/")
cp "$last_version_file" "$new_version_file"
"$cmd" "$new_version_file" & 
    wait #works with gedit but not with wine tabbed editor
[[ "$stable" ]] && 
    cp "$new_version_file" "$stable" #True if the length of string is non-zero.

Update: The following works on my pc, I will update it if improvements or solutions to unsolved problems are found:

#!/bin/bash
inc()
{
shopt -s extglob
    num=${last_version//./}
    let num++

    re=${last_version//./)(}
    re=${re//[0-9]/.}')'
    re=${re#*)}

    count=${last_version//[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
}

folder="$1"
file_pattern="$2"
cmd="$3"
stable="$4"

cd "$folder"
last_version=$(ls --format=single-column --almost-all | 
    grep "$file_pattern" | 
    sed -nr 's/^[^0-9]*(([0-9]+.)*[0-9]+).*/1/p' | 
    sort -Vu | 
    tail -n 1) #--almost-all do not list implied . and ..
last_version_file=$(ls --format=single-column --almost-all | 
    grep "$file_pattern" | 
    grep $last_version | 
    tail -n 1) #tail -n 1 is only needed to get 1 line if there are backup files with the same version number
new_version=$(inc)
new_version_file=$(echo "$last_version_file" | 
    sed -r "s/$last_version/$new_version/")
cp "$last_version_file" "$new_version_file"
"$cmd" "$new_version_file" && 
    wait #works with gedit but not tabbed wine editor
[[ "$stable" ]] && 
    cp "$new_version_file" "$stable" #True if the length of string is non-zero.

I appreciate the variety of solutions that have been offered, for they help with gaining a perspective and drawing a comparison.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
$ 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
", 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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...