web-dev-qa-db-fra.com

Erreur dans la fonction Shell pour compter les nombres pairs

Pour une affectation, je dois écrire une fonction qui imprime le nombre de nombres pairs lorsqu'elle est fournie avec une séquence de nombres.

J'ai utilisé le morceau de code que j'avais utilisé pour une affectation précédente (pour imprimer 1 quand un nombre était pair et 0 quand le nombre était impair)

Mon problème maintenant est que ma fonction continue à imprimer 0. Qu'est-ce que je fais mal?

Voici mon 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
}
12
Jedidja

Vous avez simplement oublié de remplacer $# par ($) element dans la boucle 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
}

Maintenant pour tester la fonction:

$ 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
dessert

@ dessert a trouvé le problème principal, je vais vous donner un aperçu du code:

  1. The Shebang: Il n'y a pas /usr/bin/bash dans Ubuntu. C'est /bin/bash.
  2. Il est bon que vous ayez déclaré sumlocal et évité de polluer l'espace de nom de variable en dehors de la fonction. De plus, vous pouvez déclarer une variable entière à l'aide de l'option -i:

    local -i sum=0
    
  3. Citez toujours vos variables (et paramètres)! Ce n'est pas nécessaire dans ce script, mais c'est une très bonne habitude à prendre:

    for element in "$@"
    do
    

    Cela dit, vous pouvez omettre le in "$@" ici:

    for element
    do
    

    Lorsque in <something> n'est pas indiqué, la boucle for boucle implicitement sur les arguments. Cela peut éviter des erreurs telles que l'oubli des guillemets.

  4. Il n'est pas nécessaire de calculer et de vérifier le résultat. Vous pouvez directement faire le calcul dans le if:

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

    (( ... )) est le contexte arithmétique . C'est plus utile que [[ ... ]] pour effectuer des vérifications arithmétiques, et vous pouvez en outre omettre les variables $ avant (ce qui facilite la lecture, à mon humble avis).

  5. Si vous avez déplacé la pièce même vérification dans une fonction distincte, cela pourrait améliorer la lisibilité et la réutilisabilité:

    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
muru

Je ne sais pas si vous êtes ouvert à d'autres solutions. De plus, je ne sais pas si vous pouvez utiliser des utilitaires externes ou si vous êtes uniquement limité aux commandes internes bash. Si vous pouvez utiliser grep, par exemple, votre fonction pourrait être beaucoup plus simple:

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

Cela place chaque entier en entrée sur sa propre ligne, puis utilise grep pour compter les lignes se terminant par un chiffre pair.


Mise à jour - @PeterCordes a souligné que nous pouvons même le faire sans grep - purement bash, tant que la liste en entrée contient des entiers bien formés (sans point décimal):

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

Cela fonctionne en créant une liste nommée evens en filtrant toutes les probabilités, puis en renvoyant la longueur de cette liste.

4
Digital Trauma