Для присвоения я должен записать функцию, которая печатает количество четных чисел при предоставлении последовательность чисел.
Я использовал часть кода, который я использовал для предыдущего присвоения (для печати 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
}
Вы просто забыли заменять $#
с ($
)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
@dessert нашел базовую проблему, я дам некоторый обзор кода:
/usr/bin/bash
в Ubuntu. Это /bin/bash
.Хорошо, что Вы объявили sum
local
, и загрязнение, которого избегают, переменного пространства имен вне функции. Кроме того, можно объявить это целочисленная переменная с помощью -i
опция:
local -i sum=0
Всегда заключайте свои переменные в кавычки (и параметры)! Это не необходимо в этом сценарии, но очень хорошей привычке войти:
for element in "$@"
do
Тем не менее можно опустить in "$@"
здесь:
for element
do
Когда in <something>
не дан, for
цикл неявно циклы по аргументам. Это может избежать ошибок как упущение кавычек.
Нет никакой потребности вычислить и затем проверить результат. Можно непосредственно выполнить в вычислении if
:
if (( (element % 2) == 0 ))
then
((sum = sum + 1))
fi
(( ... ))
арифметический контекст. Это более полезно, чем [[ ... ]]
для того, чтобы выполнить арифметические проверки, и дополнительно можно опустить $
перед переменными (который помогает читать, по моему скромному мнению).
При перемещении даже проверяющей части в отдельную функцию она могла бы улучшить удобочитаемость и возможность многократного использования:
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"
}
Я не уверен, открыты ли Вы для других решений. Также я не знаю, можно ли использовать внешние утилиты, или если Вы просто ограничены для избиения builtins. Если можно использовать grep
, например, Ваша функция могла быть намного более простой:
function nevens {
printf "%s\n" "$@" | grep -c '[02468]$'
}
Это помещает каждое входное целое число на его собственную строку и затем использует grep
считать строки, которые заканчиваются в ровной цифре.
Обновление - @PeterCordes указало, что мы можем даже сделать это без grep - просто чистый удар, пока входной список содержит просто хорошо сформированные целые числа (без десятичных точек):
function nevens{
evens=( ${@/%*[13579]/} )
echo "${#evens[@]}"
}
Это работает путем создания названного списка evens
путем отфильтровывания всех разногласий, затем возврата длины того списка.