Ошибка в оболочке функционирует для подсчета четных чисел

Для присвоения я должен записать функцию, которая печатает количество четных чисел при предоставлении последовательность чисел.

Я использовал часть кода, который я использовал для предыдущего присвоения (для печати 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
}
12
задан 24 April 2018 в 01:06

3 ответа

Вы просто забыли заменять $# с ($)element в for цикл:

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
20
ответ дан 23 November 2019 в 03:29

@dessert нашел базовую проблему, я дам некоторый обзор кода:

  1. Хижина: существует нет /usr/bin/bash в Ubuntu. Это /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"
    }
    
17
ответ дан 23 November 2019 в 03:29

Я не уверен, открыты ли Вы для других решений. Также я не знаю, можно ли использовать внешние утилиты, или если Вы просто ограничены для избиения builtins. Если можно использовать grep, например, Ваша функция могла быть намного более простой:

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

Это помещает каждое входное целое число на его собственную строку и затем использует grep считать строки, которые заканчиваются в ровной цифре.


Обновление - @PeterCordes указало, что мы можем даже сделать это без grep - просто чистый удар, пока входной список содержит просто хорошо сформированные целые числа (без десятичных точек):

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

Это работает путем создания названного списка evens путем отфильтровывания всех разногласий, затем возврата длины того списка.

4
ответ дан 23 November 2019 в 03:29

Другие вопросы по тегам:

Похожие вопросы: