简体   繁体   English

在bash上排序版本字符串

[英]Sort version strings on bash

Example content of STRINGS.txt: STRINGS.txt的示例内容:

    3.0.3
    3.0.11.2
    3.0.11.1
    3.0.11
    3.0.16
    3.0.15.1
    3.0.15
    3.0.14
    3.0.10.3
    3.0.10.2
    3.0.10.1
    3.0.13.1
    3.0.10
    3.0.13
    3.0.9
    3.0.12
    3.0.8
    3.0.7.2
    3.0.7.1
    3.0.7
    3.0.9.2
    3.0.9.1
    3.0.2
    3.0.8.1
    3.0.6.1
    3.0.6
    3.0.5
    3.0.1
    3.0.0

Is it possible to sort all those version strings only with bash, that the latest is on the top? 是否可以仅使用bash对所有这些版本字符串进行排序,最新版本是否在顶部?

It's possible, but a silly amount of work. 这是可能的,但却是一项愚蠢的工作。 If you have GNU sort: 如果你有GNU排序:

sort -V -r <STRINGS.txt

...will do exactly what you're asking for. ......将完全按照你的要求行事。


Now, if you really mean with no external tools, then you're getting into some trouble. 现在,如果你真的没有外部工具的意思,那么你就陷入了一些麻烦。 BlastHardcheese on Freenode's #bash IRC channel has written the following quicksort algorithm in native bash, which I've modified for readability, to factor out the compare function to be replacible, and to use Bash 4.3 namevars to be able to work with a configurable variable name (of course, this latter change means that a very new version of bash is required): Freenode的#bash IRC频道上的BlastHardcheese已经在本机bash中编写了以下quicksort算法,我为了便于阅读而修改了该算法,将compare函数分解为可重放,并使用Bash 4.3 namevars来处理可配置变量name(当然,后一个更改意味着需要一个非常新版本的bash):

# this needs to be replaced for this particular case
compare(){
  (( $1 >= $2 ))
}

swap(){
  declare -n a=$1
  local t
  t=${a[$2]}
  a[$2]=${a[$3]}
  a[$3]=$t
}

partition(){
  declare -n a=$1
  local c p x
  p=${a[$4]}
  c=$2
  swap "$1" "$3" "$4"
  for((x=$2;x<$3;x++)); do
    if ! compare "${a[x]}" "$p"; then
      swap "$1" "$x" "$c"
      ((c++))
    fi
  done
  swap "$1" "$2" "$c"
  n=$c
}

quicksort(){
  declare -n a=$1
  (( "$2" >= "$3" )) && return
  local i n
  i=$((($2+$3)/2))
  partition "$1" "$2" "$3" "$i"
  quicksort "$1" "$2" "$((n-1))"
  quicksort "$1" "$((n+1))" "$3"
}

...implement your own comparison function, and this is then adoptable. ...实现自己的比较功能,然后可以采用。

To handle only the cases you've shown here: 仅处理您在此处显示的案例:

# we want to return 0 if the first version is equal or later than the second
version_compare(){
  local -a first second

  # Let's start with trivial cases:
  if [[ $1 = "$2" ]] || [[ $1 = "$2".* ]]; then : "$1 >= $2"; return 0; fi

  IFS=. read -r -a first <<<"$1"
  IFS=. read -r -a second <<<"$2"

  local k
  for k in "${!first[@]}"; do
    local a=${first[$k]} b=${second[$k]}
    : "Evaluating field $k ($a vs $b)"
    if [[ ! $b ]]; then
      # ie. first=1.1.1, second=1.1; though this should have been handled above
      : "$1 >= $2"; return 0;
    fi
    if (( $b > $a )); then
      : "$1 < $2"; return 1;
    fi
  done

  : "$1 >= $2"; return 0;
}
compare() {
  version_compare "$2" "$1" # reverse sort order
}

To do the file IO, assuming bash 4: 要执行文件IO,假设bash 4:

readarray -t versions <STRINGS.txt
quicksort versions 0 "$(( ${#versions[@]} - 1 ))"
printf '%s\n' "${versions[@]}"

I know you don't want Python solution, but for those who lack GNU sort (such as OS X) it sure is an easy way to do this. 我知道你不需要Python解决方案,但对于那些缺乏GNU sort (比如OS X)来说,确实是一种简单的方法。

Given: 鉴于:

$ echo "$a"
3.0.3
3.0.11.2
3.0.11.1
3.0.11
3.0.16
3.0.15.1
3.0.15
3.0.14
3.0.10.3
3.0.10.2
3.0.10.1
3.0.13.1
3.0.10
3.0.13
3.0.9
3.0.12
3.0.8
3.0.7.2
3.0.7.1
3.0.7
3.0.9.2
3.0.9.1
3.0.2
3.0.8.1
3.0.6.1
3.0.6
3.0.5
3.0.1
3.0.0

Python 1 liner: Python 1班轮:

$ echo "$a" | python -c '
import sys, re; print "".join(sorted(sys.stdin.readlines(), key=lambda s: map(int, re.findall("\\d+", s)), reverse=True))'
3.0.16
3.0.15.1
3.0.15
3.0.14
3.0.13.1
3.0.13
3.0.12
3.0.11.2
3.0.11.1
3.0.11
3.0.10.3
3.0.10.2
3.0.10.1
3.0.10
3.0.9.2
3.0.9.1
3.0.9
3.0.8.1
3.0.8
3.0.7.2
3.0.7.1
3.0.7
3.0.6.1
3.0.6
3.0.5
3.0.3
3.0.2
3.0.1
3.0.0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM