字符串与浮点数的比较在shell脚本中不起作用

cdmah0mi  于 2023-08-07  发布在  Shell
关注(0)|答案(4)|浏览(117)

字符串到浮动比较在shell脚本中不起作用

REQUIRED_VERSION=2.38.0
VERSION=$(echo $FULL_DATA | cut -d ":" -f 5)   #This gives values as 2.10.0 OR 2.40

if [ $VERSION -gt $REQUIRED_VERSION ]]
  then
    echo "===  PASSED ==== "
  else
    echo "=== FAILED ==="
    #exit 1
fi

字符串
使用zsh得到如下错误
test.sh:60:错误的浮点常量
它总是给出带有sh的结果
我也试过bc,但不起作用,可能缺少语法,不确定。
请建议一些方法来从字符串类型转换为浮点数,我可以与shell或zsh进行进一步比较

kx7yvsdv

kx7yvsdv1#

版本号不是数学数字。Bash没有内置的方法来比较版本号。sort命令有-V用于比较版本号,-C用于报告文件是否正确排序。您可以将其与Bash的<<<功能一起使用,以将即时输入传递给命令:

#!/bin/bash -e

A="2.38.0"
B="2.3.1"

if sort -C -V <<<"$A"$'\n'"$B"; then
    echo "A is earlier than or the same as B."
else
    echo "A is later than B."
fi

字符串
$'\n'语法是一个用于生成换行符的Bash特性。
Bash允许你在命令前用!否定测试:

if ! sort -C -V <<<"$A"$'\n'"$B"; then


请注意,sort将报告“2.38”早于“2.38.0”。

8tntrjer

8tntrjer2#

您不能将版本作为任何类型的数字(包括浮点数)进行比较,也不能将版本作为字符串进行比较,因为每个.分隔的部分都需要单独进行数字比较。您需要将它们具体作为版本进行比较,例如:使用GNU sort for -V将版本号列表按从低到高的顺序排序:

$ cat tst.sh
#!/usr/bin/env bash

required_version=2.38.0
actual_version=10.7.45

highest_version=$(printf '%s\n%s\n' "$required_version" "$actual_version" | sort -V | tail -1)

if [[ $highest_version == $actual_version ]]; then
    echo "=== PASSED ==="
else
    echo "=== FAILED ==="
fi

字符串

$ ./tst.sh
=== PASSED ===


如果你没有GNU sort,你可以编写自己的比较函数,例如:

$ cat tst.sh
#!/usr/bin/env bash

required_version=2.38.0
actual_version=10.7.45

compare_vers() {
    local a b n

    IFS='.' read -r -a a <<< "$1"
    IFS='.' read -r -a b <<< "$2"

    (( "${#a[@]}" > "${#b[@]}" )) && n="${#a[@]}" || n="${#b[@]}"

    for (( i=0; i<n; i++ )); do
        if (( "${a[i]:0}" > "${b[i]:0}" )); then
            echo 'BIGGER'
            return
        elif (( "${a[i]:0}" < "${b[i]:0}" )); then
            echo 'SMALLER'
            return
        fi
    done

    echo 'EQUAL'
}

rslt=$(compare_vers "$actual_version" "$required_version")

if [[ $rslt == "BIGGER" ]]; then
    echo "=== PASSED ==="
else
    echo "=== FAILED ==="
fi

$ ./tst.sh
=== PASSED ===

hmtdttj4

hmtdttj43#

这可以在纯bash中完成,但当然它需要更多的代码:

required_version=2.38.0

ver2float() {
    local parts part frac=""
    IFS=. read -ra parts <<<"$1"
    for part in "${parts[@]:1}"; do
        frac+=$(printf "%03d" "$part")
    done
    printf "%s.%s" "${parts[0]}" "${frac:-0}"
}

compare_floats() {
    (( 10#${1%.*}  > 10#${2%.*} )) && return 1
    (( 10#${1%.*} <  10#${2%.*} )) && return 0
    (( 10#${1#*.} <= 10#${2#*.} ))
}

for version in  1.0  2.37.99  2.38.0  2.38.1  12; do
    if compare_floats "$(ver2float "$required_version")" \
                      "$(ver2float "$version")" 
    then
        echo "$required_version is less than or equal to $version"
    else
        echo "$required_version is greater than $version"
    fi
done

字符串
此输出

2.38.0 is greater than 1.0
2.38.0 is greater than 2.37.99
2.38.0 is less than or equal to 2.38.0
2.38.0 is less than or equal to 2.38.1
2.38.0 is less than or equal to 12

6tqwzwtp

6tqwzwtp4#

zsh附带了一个比较版本号的函数:

autoload is-at-least
is-a-least 2.38 2.0
print $?
# => 1

字符串
它可以接受点或破折号作为分隔符,看起来它也可以处理字母:

#!/usr/bin/env zsh
autoload is-at-least
tstVer(){
  local m=nope
  is-at-least ${1:?} ${2:?} && m=WORKS
  printf 'need: %-6s have: %-6s %s\n' $1 $2 $m
}
tstVer 0.3 1.0
tstVer 3 4.3-33
tstVer 4.4 4.3-33
tstVer 2.3d 2.3c
tstVer 5.3.0 5.3
tstVer 5.3 5.3.0

# => need: 0.3    have: 1.0    WORKS
# => need: 3      have: 4.3-33 WORKS
# => need: 4.4    have: 4.3-33 nope
# => need: 2.3d   have: 2.3c   nope
# => need: 5.3.0  have: 5.3    WORKS
# => need: 5.3    have: 5.3.0  WORKS

相关问题