shell 函数计算偶数时出错

shell 函数计算偶数时出错

对于一项作业,我必须编写一个函数,当提供一系列数字时,该函数会打印偶数的数量。

我使用了之前作业中使用的一段代码(用于打印1数字为偶数和0奇数时的情况)

我现在的问题是我的函数一直在打印0。我做错了什么?

这是我的脚本:

#!/usr/bin/bash
# File: nevens.sh

# Write a function called nevens which prints the number of even numbers when provided with a sequence of numbers.
# Check: input nevens 42 6 7 9 33 = output 2

function nevens {

        local sum=0

        for element in $@
        do
                let evencheck=$(( $# % 2 ))
                if [[ $evencheck -eq 0 ]]
                then
                        let sum=$sum+1
                fi
        done

        echo $sum
}

答案1

您只是忘了在循环$#中用 ( $)替换:elementfor

function nevens {
  local sum=0
  for element in $@; do
    let evencheck=$(( element % 2 ))
    if [[ $evencheck -eq 0 ]]; then
      let sum=sum+1
    fi
  done
  echo $sum
}

现在测试该功能:

$ nevens 42 6 7 9 33
2
$ nevens 42 6 7 9 33 22
3
$ nevens {1..10..2} # 1 to 10 step 2 → odd numbers only
0
$ nevens {2..10..2} # 2 to 10 step 2 → five even numbers
5

答案2

@甜点找到核心问题后,我来给出一些代码回顾:

  1. 概要:Ubuntu 中没有/usr/bin/bash。它是/bin/bash
  2. 声明了 很好sum local,避免了污染函数外部的变量命名空间。此外,您可以使用以下-i选项将其声明为整数变量:

    local -i sum=0
    
  3. 一定要引用你的变量(和参数)!在这个脚本中这不是必需的,但是养成一个非常好的习惯:

    for element in "$@"
    do
    

    也就是说,你可以省略in "$@"这里:

    for element
    do
    

    in <something>没有给出时,for循环会隐式地循环遍历参数。这可以避免诸如忘记引号之类的错误。

  4. 无需计算然后检查结果。您可以直接在中进行计算if

    if (( (element % 2) == 0 ))
    then
        ((sum = sum + 1))
    fi
    

    (( ... ))算术语境。它比执行算术检查更有用[[ ... ]],另外您还可以省略$之前的变量(在我看来,这使得它更容易阅读)。

  5. 如果将均匀检查部分移到单独的函数中,可能会提高可读性和可重用性:

    function evencheck
    {
        return $(( $1 % 2 ))
    }
    function nevens
    {
        local -i sum=0
        for element
        do
            # `if` implicitly checks that the returned value/exit status is 0
            if evencheck "$element"
            then
                (( sum++ ))
            fi
        done
        echo "$sum"
    }
    

答案3

我不确定您是否愿意接受其他解决方案。另外,我不知道您是否可以使用外部实用程序,或者您是否仅限于使用 bash 内置程序。grep例如,如果您可以使用,您的函数可能会简单得多:

function nevens {
    printf "%s\n" "$@" | grep -c '[02468]$'
}

将每个输入整数放在其自己的行上,然后用来grep计算以偶数结尾的行数。


更新 - @PeterCordes 指出我们甚至可以不使用 grep 来做到这一点 - 只需纯 bash,只要输入列表包含格式正确的整数(没有小数点):

function nevens{
    evens=( ${@/%*[13579]/} )
    echo "${#evens[@]}"
}

它的工作原理是创建一个列表,evens过滤掉所有的几率,然后返回该列表的长度。

相关内容