从bash中的排序列表中选择
我有一个目录,其中大部分是版本号,我正试图确定一个是在另一个特定版本之前排序的版本 这里的背景是,为了避免出现XY问题,这些版本号来自web内容的git标记,我们将站点虚拟主机的从bash中的排序列表中选择,bash,sorting,Bash,Sorting,我有一个目录,其中大部分是版本号,我正试图确定一个是在另一个特定版本之前排序的版本 这里的背景是,为了避免出现XY问题,这些版本号来自web内容的git标记,我们将站点虚拟主机的public\uHTML目录符号链接到版本目录 它看起来像这样: 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 w
public\uHTML
目录符号链接到版本目录
它看起来像这样:
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
read target <<<"$(stat -f'%Y' "${base}/public_html")"
target="$(stat -c '%N' "${base}/public_html")"
target="${target#* -> ?}"; target="${target%?}"
符号链接可能并不总是指向最新版本(例如,如果我们不得不放弃更改)。我的目标是找到正确命名的目录(即,我们将跳过*-fail
等),该目录在public\u html
指向的目录之前进行版本排序
我在FreeBSD中,因此我的stat
命令的工作原理如下:
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
read target <<<"$(stat -f'%Y' "${base}/public_html")"
target="$(stat -c '%N' "${base}/public_html")"
target="${target#* -> ?}"; target="${target%?}"
但从这里开始,我不确定如何收集版本号。请注意,我在FreeBSD中,因此我的sort
命令没有-V
选项。我试过两种方法
第一个是在目录内容上处理while循环:
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)
shopt-s extglob
读这篇文章的时候;做
[[“$this”=“$target”]&&break
上一个“$this”
完成<$(ls-1d v+([0-9])。+([0-9])。+([0-9])|排序-n-t-k1,1-k2,2-k3,3)
第二个非常类似,而是解析数组:
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
shopt-s extglob
a=($(ls-1d v+([0-9])。+([0-9])。+([0-9])|排序-n-t-k1,1-k2,2-k3,3))
对于((n=0;n可能不是一个完整的解决方案,但您可能可以通过以下方式逃脱:
ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -t . -k1,1 -k2,2n -k3,3n
这里的区别在于,数字字段的-n
仅应用于第二个和第三个字段,因此您将继续按字母顺序对第一个字段进行排序
这对你从v9.x.x
跳到v10.x.x
没有帮助,但是当你在不到三年的时间里从v2
跳到v4
时,也许它“足够好了”
此外:
- 您可以分两个阶段运行此操作。第一阶段使用类似于
major=$(ls-1d v[0-9]*|tail-1);major=${major%%.*}”
,确定最新的主要版本号,然后后续排序基于a=$(ls${major}+([0-9])+([0-9])
。然后您可以安全地仅对数字字段进行排序
- 为了使bash完全内部化,您可以对其进行调整。这需要进行一些黑客操作,才能使其与您的阵列一起工作
也许不是一个完整的解决方案,但您可以通过以下方式摆脱:
ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -t . -k1,1 -k2,2n -k3,3n
这里的区别在于,数字字段的-n
仅应用于第二个和第三个字段,因此您将继续按字母顺序对第一个字段进行排序
这对你从v9.x.x
跳到v10.x.x
没有帮助,但是当你在不到三年的时间里从v2
跳到v4
时,也许它“足够好了”
此外:
- 您可以分两个阶段运行此操作。第一阶段使用类似于
major=$(ls-1d v[0-9]*|tail-1);major=${major%%.*}”
,确定最新的主要版本号,然后后续排序基于a=$(ls${major}+([0-9])+([0-9])
。然后您可以安全地仅对数字字段进行排序
- 为了使bash完全内部化,您可以对其进行调整。这需要进行一些黑客操作,才能使其与您的阵列一起工作
您可以分离alpha前缀,按子字段进行数字排序,然后再合并回来
$ ls -1 v* | sed 's/^v/v./' | sort -t. -k2,2n -k3,3n -k4n | sed 's/^v\./v/'
v2.0.8
v2.0.9
v2.0.10
v2.0.11
v4.2.0
v4.19.0
v4.20.0
v4.20.0-fail
v4.20.1
v4.26.1
v4.35.0
v4.36.0
v10.0.1
请注意,我添加了v10.*以验证它是未来的证明。您可以分离alpha前缀,按子字段进行数字排序,然后合并回来
$ ls -1 v* | sed 's/^v/v./' | sort -t. -k2,2n -k3,3n -k4n | sed 's/^v\./v/'
v2.0.8
v2.0.9
v2.0.10
v2.0.11
v4.2.0
v4.19.0
v4.20.0
v4.20.0-fail
v4.20.1
v4.26.1
v4.35.0
v4.36.0
v10.0.1
请注意,我添加了v10.*以验证它是否经得起未来的考验。这个纯Bash(除了readlink
)解决方案执行线性搜索而不是排序:
VERSION_RX='^v([0-9][0-9]*)\.([0-9][0-9]*)\.([0-9][0-9]*)$'
target=$(readlink "$base/public_html")
# target == v1.22.333 -> target_key == 000000001_000000022_000000333
[[ $target =~ $VERSION_RX ]] || exit 1
printf -v target_key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
pred_dir=
pred_key=
for path in "$base"/v*.*.* ; do
dir=${path##*/}
[[ $dir == "$target" ]] && continue
[[ $dir =~ $VERSION_RX ]] || continue
printf -v key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
[[ $key > $target_key ]] && continue
if [[ -z $pred_key || $key > $pred_key ]] ; then
pred_dir=$dir
pred_key=$key
fi
done
echo "$pred_dir"
此纯Bash(除了readlink
)解决方案执行线性搜索而不是排序:
VERSION_RX='^v([0-9][0-9]*)\.([0-9][0-9]*)\.([0-9][0-9]*)$'
target=$(readlink "$base/public_html")
# target == v1.22.333 -> target_key == 000000001_000000022_000000333
[[ $target =~ $VERSION_RX ]] || exit 1
printf -v target_key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
pred_dir=
pred_key=
for path in "$base"/v*.*.* ; do
dir=${path##*/}
[[ $dir == "$target" ]] && continue
[[ $dir =~ $VERSION_RX ]] || continue
printf -v key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
[[ $key > $target_key ]] && continue
if [[ -z $pred_key || $key > $pred_key ]] ; then
pred_dir=$dir
pred_key=$key
fi
done
echo "$pred_dir"
您在哪里看到使用的-v
选项?这是缺少版本选项的解决办法。您在哪里看到使用的-v
选项?这是缺少版本选项的解决办法。