Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从bash中的排序列表中选择_Bash_Sorting - Fatal编程技术网

从bash中的排序列表中选择

从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

我有一个目录,其中大部分是版本号,我正试图确定一个是在另一个特定版本之前排序的版本

这里的背景是,为了避免出现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  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
选项?这是缺少版本选项的解决办法。