#!/bin/sh set -e # accepts two semantic-ish versions and echoes a character representing the # relationship between the two. # "semantic-ish" means here "a superset of semantic versioning." all correctly # constructed semantic versions should compare in accordance with version 2.0 of # the semver.org spec. versions that do not conform to the spec may also # compare correctly. the primary difference is that there is no limitation on # the number of version fields. comparever() { comparever_default $@; } # a split definition allows other formats to use this function to define their # own comparever functions if they wish. comparever_default() { v1="$1" v2="$2" # strip any trailing meta tags v1="${v1%+*}" v2="${v2%+*}" # equal? [ "$v1" != "$v2" ] || { echo "=" && return 0; } # strip leading characters that match. while [ "$(echo "$v1" | cut -c1)" = "$(echo "$v2" | cut -c1)" ]; do v1="$(echo "$v1" | cut -c2-)" v2="$(echo "$v2" | cut -c2-)" done v1head="$(echo "$v1" | cut -c1)" v2head="$(echo "$v2" | cut -c1)" # if the difference is a prerelease tag, the prerelease is lesser. case "$v1head" in -) echo '<' && return 0;; esac case "$v2head" in -) echo '>' && return 0;; esac # otherwise, if one is a prefix of the other, the other is greater. [ -n "$v1" ] || { echo '<' && return 0; } [ -n "$v2" ] || { echo '>' && return 0; } # otherwise, if one starts with a dot, the other is the greater. case "$v1head" in .) echo '<' && return 0;; esac case "$v2head" in .) echo '>' && return 0;; esac # strip any remaining version fields v1="$(echo "$v1" | sed s/\\..*\$//)" v2="$(echo "$v2" | sed s/\\..*\$//)" # if the version tails are numeric, compare numerically. (ignore prerelease # tags.) otherwise, compare lexically. if (echo "${v1%-*}${v2%-*}" | grep -q "^[0-9]\+\$"); then [ "$(echo "${v1%-*}")" -gt "$(echo "${v2%-*}")" ] \ && echo ">" \ || echo "<" else # v1 and v2 contain only the differences. using 'cut' and tabs here to # perform a lexical sort on the differences and retrieve the original # string associated with the greater of the two remainders. greater=$(printf "%s\t%s\n%s\t%s" "$v1" "$1" "$v2" "$2" \ | sort | tail -n1 | cut -f2) [ "$greater" = "$1" ] && echo ">" || echo "<" fi }