【问题标题】:Sorting not working correctly in bash排序在 bash 中无法正常工作
【发布时间】:2023-03-10 04:14:01
【问题描述】:

我有一个变量 VarExp 具有以下 2 个值

1.5.2
1.5.3

我有另一个变量 VarCurr 具有以下 1 个值

1.8.1

我想将VarCurrVarExp 进行比较,并且仅在以下情况下才想echo SUCCESS

VarCurr >= VarExp

我编写了以下代码,但它总是返回FAILURE

VarExp='1.5.2 1.5.3'
VarCurr='1.8.1'

printf -v versions '%s\n%s' "$VarExp" "$VarCurr"
if [[ $versions = "$(sort -V <<< "$versions")" ]]; then
    echo 'FAILURE'
else
    echo 'SUCCESS'
fi

VarCurr 需要 >= VarExp 中包含的最小值

【问题讨论】:

  • 我注意到您使用的是赋值而不是相等运算符。当条件满足时,你确定不想要成功吗?
  • 当然,条件满足我要'SUCCESS'
  • @argx =bash 中的相等运算符。条件表达式中没有赋值。
  • @Barmar 很好的信息,我的错误。还有一个SO question about it。感谢您指出这一点。
  • 我认为你有成功和失败倒退。 $VarCurr 高于 $VarExp,所以它排在它之后,这就是你在 $versions 中的顺序。所以当它等于排序结果时,应该是SUCCESS,而不是`FAILURE。

标签: bash shell awk sed grep


【解决方案1】:

使用 GNU 对-V 进行排序:

$ cat tst.sh
#!/bin/bash
varExp='1.5.2 1.5.3'
varCurr=$1

minVarExp=$(printf '%s\n' $varExp | sort -V | head -1)
maxOfVers=$(printf '%s\n' "$minVarExp" "$varCurr" | sort -V | tail -1)

if [[ $maxOfVers = $varCurr ]]; then
    echo 'SUCCESS'
else
    echo 'FAILURE'
fi

$ ./tst.sh 1.8.1
SUCCESS

$ ./tst.sh 1.5.1
FAILURE

$ ./tst.sh 1.5.2
SUCCESS

【讨论】:

    【解决方案2】:

    我建议使用能够正确客观化版本对象并且可以理解major.minor.build.revision 的语言。这是一个从 Perl 借用的 bash 脚本示例来进行版本解析:

    #!/bin/bash
    
    VarExp='1.5.2 1.5.3'
    VarCurr='1.8.1'
    
    for i in $VarExp; do {
        perl -e 'use version;exit !(version->parse('$VarCurr') >= version->parse('$i'));' && {
            echo 'SUCCESS'
            exit
        }
    }; done
    
    echo 'FAILURE'
    exit
    

    当然,用 Perl 编写整个内容可能更优雅。

    编辑:这是另一个使用 Python 的示例:

    #!/bin/bash
    
    VarExp='1.5.3 1.5.6'
    VarCurr='1.5.3'
    
    for i in $VarExp; do {
        python -c 'from distutils.version import LooseVersion;\
        exit(LooseVersion("'$VarCurr'") >= LooseVersion("'$i'"))' || {
            echo 'SUCCESS'
            exit
        }
    }; done
    
    echo 'FAILURE'
    exit
    

    【讨论】:

    • 我得到的输出为FAILURE 它应该是SUCCESS 我正在使用值VarCurr='1.5.3'VarExp='1.5.3 1.5.6'
    • @meallhour 奇数。对于我来说,这些值按预期工作。这些变量是您更改的唯一代码吗?
    • 当我执行echo $VarCurr 时,我得到1.5.3 同样,当我执行echo $VarExp 时,我得到1.5.3 1.5.6 有了这些值,我仍然得到FAILURE
    • VarCurr 需要 >= VarExp 中包含的最小值
    • 我已经重新启动服务器,之后它工作正常。谢谢你的帮助!!
    【解决方案3】:

    如果您使用 bash,则可以使用数组。它们使处理列表变得更加容易和安全。此外,由于您不能依赖像 sort -V 这样的功能可用性来实现可移植性,因此一种选择可能是将您的数字转换为更适合 bash 比较的数字。以下假设您的字符串中的任何数字都不会大于 3 位。盐调味。

    #!/bin/bash
    
    VarExp='1.5.2 1.5.3'
    VarCurr='1.8.1'
    
    a=( $VarExp )
    
    function padsemver {
        local IFS=.
        local -a a=()
        read -a a <<<"$1"
        printf '%03d' "${a[@]}"
    }
    
    x="$(padsemver "$VarCurr")"
    
    for i in "${a[@]}"; do
        if [[ 10#"$x" -gt 10#"$(padsemver $i)" ]]; then
            printf '%s\n' "SUCCESS"
            exit 0
        fi
    done
    
    printf '%s\n' "FAILURE"
    exit 1
    

    这使用padsemver() 函数将1.5.3 转换为001005003,这使其与test[[ 中的数字比较兼容。 (10# 确保以 0 开头的数字将被解释为十进制而不是八进制。)

    如果你需要的话,你当然可以把整个测试放到它自己的函数中,而不是一个独立的脚本中。

    【讨论】:

      【解决方案4】:

      您能否尝试关注一下,如果这对您有帮助,请告诉我。

      varExp="1.5.2
      1.5.4"
      VarCurr="1.8.1"
      echo "$varExp" |
      awk -v current="$VarCurr" '{
        curr=current
        value=$0
        gsub(/\./,"",curr)
        gsub(/\./,"",value)
        if(curr>=value){
          print "SUCCESS, value of varExp " current " is more than variable varExp " $0"."
        }
      }'
      

      输出如下。

      SUCCESS, value of varExp 1.8.1 is more than variable varExp 1.5.2.
      SUCCESS, value of varExp 1.8.1 is more than variable varExp 1.5.4.
      

      假设名为varExp 的变量在新行中有数值,因此通过将其值包装在" 中将保持新行在其中。

      【讨论】:

      • 去除点并不总是有效。当次要版本达到 10 时会发生什么? 1.10.0 > 1.5.2,但 awk 将执行 1100 和 152 的字符串比较,为 152 分配更高的值。至少在我的系统上它在 gawk 中是这样的。无论如何,都会有一些歧义。 1.08.1 的排序应该高于 1.5.2,但在编写代码时不会排序。
      猜你喜欢
      • 2020-12-14
      • 2012-03-29
      • 2018-07-18
      • 1970-01-01
      • 2015-04-05
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 2016-01-24
      相关资源
      最近更新 更多