Para uma tarefa, tenho que escrever uma função que imprima o número de números pares quando fornecida com uma sequência de números.
Usei o código que usei para uma tarefa anterior (para imprimir 1
quando um número era par e 0
quando o número era ímpar)
Meu problema agora é que minha função continua imprimindo 0
. O que estou fazendo de errado?
Aqui está o meu script:
#!/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
}
Respostas:
Você esqueceu de substituir
$#
por ($
)element
nofor
loop:Agora, para testar a função:
fonte
A @dessert encontrou o problema principal, darei uma revisão de código:
/usr/bin/bash
no Ubuntu. É/bin/bash
.É bom que você tenha declarado
sum
local
e evitado poluir o espaço para nome da variável fora da função. Além disso, você pode declarar uma variável inteira usando a-i
opção:Sempre cite suas variáveis (e parâmetros)! Não é necessário neste script, mas um hábito muito bom de entrar:
Dito isto, você pode omitir o
in "$@"
aqui:Quando
in <something>
não é fornecido, ofor
loop envolve implicitamente os argumentos. Isso pode evitar erros como esquecer as aspas.Não há necessidade de calcular e verificar o resultado. Você pode fazer o cálculo diretamente no
if
:(( ... ))
é o contexto aritmético . É mais útil do que[[ ... ]]
para executar verificações aritméticas e, além disso, você pode omitir as$
variáveis anteriores (o que facilita a leitura, IMHO).Se você moveu a parte de verificação uniforme para uma função separada, isso pode melhorar a legibilidade e a reutilização:
fonte
sum=$((sum + 1 - element % 2))
.&1
para verificar a parte mais baixa, se for mais legível para você). Mas podemos torná-lo mais legível:sum=$((sum + !(element&1) ))
usar um inverso booleano em vez de+1 - condition
. Ou apenas conte os elementos ímpares com((odd += element&1))
, e no final imprima comecho $(($# - element))
, porqueeven = total - odd
.local -i
esum++
.Não tenho certeza se você está aberto a outras soluções. Também não sei se você pode usar utilitários externos ou se está puramente limitado a bash de componentes internos. Se você pode usar
grep
, por exemplo, sua função pode ser muito mais simples:Isso coloca cada número inteiro de entrada em sua própria linha e depois
grep
conta as linhas que terminam em um dígito par.Atualização - @PeterCordes apontou que podemos fazer isso sem grep - apenas bash puro, desde que a lista de entrada contenha apenas números inteiros bem formados (sem pontos decimais):
Isso funciona criando uma lista chamada
evens
, filtrando todas as probabilidades e retornando o comprimento dessa lista.fonte
3.0
como um número par; a pergunta não era precisa sobre qual seria a forma dos números.${/%/}
a@
matriz para exigir uma correspondência no final da sequência, dentro de um inicializador de matriz. Imprima a contagem. Como um one-liner para definir e executá-lo:foo(){ evens=( ${@/%*[13579]/} ); echo "${#evens[@]} even numbers"; printf "%s\n" "${evens[@]}"; }; foo 135 212 325 3 6 3 4 5 9 7 2 12310
. Inclui realmente imprimir a lista para depuração. Prints5 even numbers 212 6 4 2 12310
(nas linhas de setembro)grep
fosse realmente mais rápido do quebash
. Hmm, eu me pergunto se há uma pergunta codegolf onde eu poderia postar essa função bash: P