对这样的列表进行排序的最简单方法是什么

对这样的列表进行排序的最简单方法是什么

我试图确定给定节点上哪个版本的 DB2 是最新的。我们将 DB2 软件安装在 /opt/IBM/db2 目录中。如果我列出我得到的目录

V10.5
V9.1
V9.5
V9.5fp10
V9.7
V9.7fp3
V9.7fp6
V9.7fp7

显然 10.5 是当前最新版本,但第一个条目并不总是最新的(即:当我们安装 V11.0 时)。有没有一种相对简单的方法来确定最新的(在 ksh93 中)?我可以将每个条目解析为主要/次要/修复包,但这似乎是劳动密集型的。

答案1

如果你有 GNU 工具,你可以使用ls -v

或者,使用 perl:

printf "%s\n" * | perl -e '
    @sorted = map {$_->[1]}
              sort {$a->[0] <=> $b->[0] or $a->[1] cmp $b->[1]}
              map {/(\d+\.\d*)/ and [$1, $_]}
              <>;
    print $sorted[-1];
'

答案2

没有 GNU 工具,只有劳动密集型的 shell 脚本:

recentdb2 () (
  cd /opt/IBM/db2 || return 1
  highest=
  himajor=
  himinor=
  hifp=

  for dir in V*.*
  do
        [ ! -d "$dir" ] && continue
        nov="${dir#V*}"
        major="${nov%%.*}"
        notmajor="${nov##*.}"
        minor="${notmajor%%fp*}"
        if [ "$minor" = "$notmajor" ]
        then
                # no FP
                fp=0
        else
                fp="${notmajor##*fp}"
        fi

        # if highest major isn't set, set it and continue
        # else compare major; if higher, set it and continue
        # else compare minor; if higher, set it and continue
        # else compare fp; if higher, set it

        if [ "${himajor:-notset}" = "notset" ]
        then
                highest="$dir"
                himajor="$major"
                himinor="$minor"
                hifp="$fp"
                continue
        fi

        if [ "$major" -gt "$himajor" ]
        then
                highest="$dir"
                himajor="$major"
                himinor="$minor"
                hifp="$fp"
                continue
        elif [ "$major" -eq "$himajor" ] && [ "$minor" -gt "$himinor" ]
        then
                highest="$dir"
                himajor="$major"
                himinor="$minor"
                hifp="$fp"
                continue
        elif [ "$major" -eq "$himajor" ] && [ "$minor" -eq "$himinor" ] && [ "$fp" -gt "$hifp" ]
        then
                highest="$dir"
                himajor="$major"
                himinor="$minor"
                hifp="$fp"
        fi
        # else, the current value is less than the highest value, drop it and continue on
  done
  printf "%s" "$highest"
)

这定义了一个函数,它将(尝试)从 /opt/IBM/db2 返回最高级别的 DB2 目录。

该函数全部在子 shell 中运行,因此:

  • 它创建的变量在完成时消失,并且
  • cd与子 shell 隔离

然后,该函数循环访问 /opt/IBM/db2 目录中与 glob 模式匹配的条目V*.*—— 如果您有诸如V11不带任何点的版本,请调整此项。第一个测试是确保我们不会被流浪者愚弄文件匹配这个模式。

劳动开始:我们剥去前导V(“无 V”),然后计算:

  • 主数字是第一个句点之前的所有内容
  • “非主要数字”是第一个周期之后的所有内容
  • 次要编号是从“非主要编号”到任何一个的部分fp
  • 如果名称中有一个fp(从完整的“非主要数字”字符串到次要数字没有变化),则将 fp 设置为该名称,否则将其设置为零

正如评论所说,我们测试并适当设置“高”变量。我们遇到的第一个目录将进入第一个条件——默认情况下它是最高级别。

然后将后续目录条目与当前最高的主要版本、次要版本和 fp 版本进行比较。

循环完成后,该函数将打印出最新的目录名称。

通过创建脚本或在代码中获取来使用该函数,然后调用该函数:

h=$(recentdb2)

答案3

zsh

list=(/opt/IBM/db2/V*(Nn:t))

其中nglob 限定符启用数字排序完全符合您的要求,这里从最旧的 ( $list[1]) 到最新的 ( $list[-1]) 排序。

ksh93,如果它是用ls内置的构建的ast-open,您可以使用它版本种类:

(cd /opt/IBM/db2 && command /opt/ast/bin/ls -d -y version V*)

command /opt/ast/bin/ls调用该/opt/ast/bin/ls命令或相应的内置等效命令(如果存在),无论/opt/ast/bin/ls文件系统上是否存在。

您还可以这样做:

PATH=/opt/ast/bin:$PATH
ls -d -y version V*

为了使该ls内置函数优先于系统中的/bin/usr/bin

否则,你可以这样做:

tmp=(/opt/IBM/db2/~(N)V*) # ~(N) equivalent of zsh's N
tmp=("${tmp[@]##*/}")     # equivalent of :t
typeset -A map

# build an associative array where the key is the element with
# all the numbers in them 0-padded to 20 digits. Append a counter
# to make sure all keys are unique.
typeset -Z 20 n=0
for i in "${tmp[@]}"; do
  k=${i//+([0-9])/00000000000000000000\1}
  k=${k//+(0){20}([0-9])/\2}
  map[$k-$n]=$i
  ((n++))
done

# sort the keys of the associative array into $@:
set -s -- "${!map[@]}"

# fill $list with the values for those (now sorted) keys.
typeset -a list
for i do
  list+=("${map[$i]}")
done
printf -- '- %s\n' "${list[@]}"
((${#list[@]})) && printf 'Newest: %s\n' "${list[@]: -1}"

在你的样本上,这给出了:

- V9.1
- V9.5
- V9.5fp10
- V9.7
- V9.7fp3
- V9.7fp6
- V9.7fp7
- V10.5
Newest: V10.5

相关内容