I have a directory of mostly version numbers, and I'm trying to determine the one that is version-sorted just before another particular one.
The background here, for fear of making this an XY problem, is that these version numbers are derived from git tags for web content, and we symlink the public_html
directory for the site's virtualhost to the versioned directory.
It looks something like this:
drwxr-xr-x 8 graham www 17 Oct 17 2013 v2.0.10
drwxr-xr-x 8 graham www 17 Oct 17 2013 v2.0.11
drwxrwxr-x 8 graham www 17 Aug 29 2013 v2.0.8
drwxr-xr-x 8 brian www 17 Oct 17 2013 v2.0.9
...
drwxr-xr-x 9 graham www 21 Aug 5 2015 v4.19.0
drwxr-xr-x 10 graham www 19 Dec 17 2014 v4.2.0
drwxr-xr-x 9 brian www 21 Aug 10 2015 v4.20.0
drwxr-xr-x 9 brian www 21 Aug 10 2015 v4.20.0-fail
drwxr-xr-x 9 graham www 21 Aug 11 2015 v4.20.1
...
drwxr-xr-x 9 graham www 19 Mar 14 11:00 v4.35.0
drwxr-xr-x 9 graham www 19 Mar 14 13:28 v4.36.0
drwxr-xr-x 9 graham www 19 Mar 16 10:58 v4.36.1
lrwxr-xr-x 1 graham www 11 Mar 16 11:13 public_html -> v4.36.1
The symlink may not always be pointing at the most recent version (for example if we had to back out of a change). My goal is to find the properly-named directory (i.e. we'd skip *-fail
and the like) that is version sorted before the one that public_html
points to.
I'm in FreeBSD, so my stat
command works nicely like this:
read target <<<"$(stat -f'%Y' "${base}/public_html")"
If you're in Linux, I gather you could get the same effect with something like this:
target="$(stat -c '%N' "${base}/public_html")"
target="${target#* -> ?}"; target="${target%?}"
But from here, I'm not sure how I gather the version number. Note that I'm in FreeBSD, so my sort
command does not have a -V
option. I've tried two methods.
The first is to process a while loop on the directory contents:
shopt -s extglob
while read this; do
[[ "$this" = "$target" ]] && break
previous="$this"
done < $(ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -n -t . -k1,1 -k2,2 -k3,3)
The second is pretty similar, parsing an array instead:
shopt -s extglob
a=( $(ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -n -t . -k1,1 -k2,2 -k3,3) )
for (( n=0; n<${#a[@]}; n++ )); do
[[ "${a[$n]}" = "$target" ]] && break
previous="${a[$n]}"
done
Where both of these fall down is the sort
, in which the first field does not appear to be sorted. I suspect it's because it's not numeric (with "v" at the start, delimited by "."). Is there a way I can specify multiple delimiters, or otherwise "ignore" the v
somehow?
Or is there a better way to handle this than using the external sort
command, which has non-portable options? Something internal to bash perhaps?
Thanks.