Para una tarea, tengo que escribir una función que imprima el número de números pares cuando se proporciona una secuencia de números.
Usé el código que usé para una tarea anterior (para imprimir 1cuando un número era par y 0cuando el número era impar)
Mi problema ahora es que mi función sigue imprimiendo 0. ¿Qué estoy haciendo mal?
Aquí está mi guión:
#!/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
}

Respuestas:
Simplemente olvidó reemplazar
$#con ($)elementen elforbucle:Ahora para probar la función:
fuente
@dessert ha encontrado el problema central, daré una revisión de código:
/usr/bin/bashen Ubuntu. Es/bin/bash.Es bueno que hayas declarado
sumlocaly evitado contaminar el espacio de nombres variable fuera de la función. Además, puede declararlo como una variable entera utilizando la-iopción:¡Siempre cita tus variables (y parámetros)! No es necesario en este script, pero es un muy buen hábito para entrar:
Dicho esto, puedes omitir el
in "$@"aquí:Cuando
in <something>no se proporciona, elforbucle recorre implícitamente los argumentos. Esto puede evitar errores como olvidar las comillas.No hay necesidad de calcular y luego verificar el resultado. Puedes hacer el cálculo directamente en
if:(( ... ))Es el contexto aritmético . Es más útil que[[ ... ]]para realizar comprobaciones aritméticas, y además puede omitir las$variables anteriores (lo que hace que sea más fácil de leer, en mi humilde opinión).Si movió la parte de verificación uniforme a una función separada, podría mejorar la legibilidad y la reutilización:
fuente
sum=$((sum + 1 - element % 2)).&1verificar el bit bajo si eso es más legible para usted). Pero podemos hacerlo más legible:sum=$((sum + !(element&1) ))usar un inverso booleano en lugar de+1 - condition. O simplemente cuente los elementos impares con((odd += element&1)), y al final imprima conecho $(($# - element)), porqueeven = total - odd.local -iysum++.No estoy seguro si estás abierto a otras soluciones. Además, no sé si puede utilizar utilidades externas, o si está limitado exclusivamente a bash builtins. Si puede usar
grep, por ejemplo, su función podría ser mucho más simple:Esto coloca cada número entero de entrada en su propia línea y luego usa
greppara contar las líneas que terminan en un dígito par.Actualización: @PeterCordes señaló que incluso podemos hacer esto sin grep, solo bash puro, siempre que la lista de entrada contenga enteros bien formados (sin puntos decimales):
Esto funciona creando una lista llamada
evensal filtrar todas las probabilidades y luego devolver la longitud de esa lista.fuente
3.0como un número par; la pregunta no era precisa sobre qué forma tomarían los números.${/%/}la@matriz para requerir una coincidencia al final de la cadena, dentro de un inicializador de matriz. Imprime el recuento. Como de una sola línea para definir y ejecutar:foo(){ evens=( ${@/%*[13579]/} ); echo "${#evens[@]} even numbers"; printf "%s\n" "${evens[@]}"; }; foo 135 212 325 3 6 3 4 5 9 7 2 12310. Incluye imprimir realmente la lista para la depuración. Impresiones5 even numbers 212 6 4 2 12310(en líneas sep.)grepfuera realmente más rápido quebash. Hmm, me pregunto si hay una pregunta de codegolf donde podría publicar esa función bash: P