J'essaye de refactoriser ce code:

if [ $(($1 % 4)) -eq 0 ] && [ $(($1 % 100)) -ne 0 ] || [ $(($1 % 400)) -eq 0 ] ; then
    echo $T
else
    echo $F
fi

En quelque chose comme ça:

if divisibleBy4 && notDivisibleBy100 || divisibleBy400; then
    echo $T
else
    echo $F
fi

Notez que

T="true"
F="false"

La fonction divisibleBy4 ressemble à:

divisibleBy4() {
    return  [ $(($1 % 4)) -eq 0 ]
}

Mais j'ai essayé plusieurs itérations, y compris ce que je pensais fonctionnerait certainement.

divisibleBy4() {
    if [ $(($1 % 4)) -eq 0  ]; then
    return 1
    else return 0
    fi
}

Une idée comment corriger correctement la syntaxe afin que je puisse les refactoriser en fonctions et les utiliser dans mon instruction if?

Lors du test, je vois l'erreur

erreur de syntaxe: opérande attendu (le jeton d'erreur est "% 4")

Une autre chose que j'ai essayée est, mais ne semble toujours pas fonctionner:

INPUT=$1

divisibleBy4() {
    if [ $(($INPUT % 4)) -eq 0  ]; then
         return 1
    else return 0
    fi
}

notDivisibleBy100() {
    if [ $(($INPUT % 100)) -ne 0]; then
         return 1
    else return 0
    fi
}

divisibleBy400() {
    if [ $(($INPUT % 400)) -eq 0  ]; then
         return 1
    else return 0
    fi
}


if divisibleBy4 && notDivisibleBy100 || divisibleBy400; then
    echo $T
else
    echo $F
fi

Ou

INPUT=$1

divisibleBy4() {
    return $((!($INPUT %4)))
}
notDivisibleBy100() {
    return $(($INPUT %100))
}
divisibleBy400() {
    return $((!($INPUT %400)))
}

(( divisibleBy4 && notDivisibleBy100 || divisibleBy400 )) && echo "true" || echo "false"
0
Turnipdabeets 26 janv. 2019 à 22:28

3 réponses

Meilleure réponse

La réponse la plus simple et la plus directe est de créer simplement des fonctions qui consistent uniquement en tests eux-mêmes:

INPUT=$1

divisibleBy4() {
    [ $(($INPUT % 4)) -eq 0  ]
}

notDivisibleBy100() {
    [ $(($INPUT % 100)) -ne 0 ]
}

divisibleBy400() {
    [ $(($INPUT % 400)) -eq 0  ]
}

La raison pour laquelle cela fonctionne est qu'une fonction sans return renverra implicitement le statut de la dernière commande de la fonction; dans ces cas, c'est la commande de test (note: [ est une commande, même si elle n'en a pas l'air), donc les fonctions renvoient simplement le résultat du test directement.

Je ferais au moins un changement à ceux-ci, cependant: ils testent tous la valeur de la variable shell INPUT; il est préférable de transmettre les données sur lesquelles les fonctions opèrent en tant que paramètres. Ainsi, il serait préférable de faire quelque chose comme ceci:

divisibleBy4() {
    [ $(($1 % 4)) -eq 0  ]
}

if divisibleBy4 "$1" ...

Plutôt que cela:

divisibleBy4() {
    [ $(($INPUT % 4)) -eq 0  ]
}

INPUT=$1
if divisibleBy4 ...

Notez que vous pouvez également regrouper toute l'année bissextile de la même manière:

isLeapYear() {
    [ $(($1 % 4)) -eq 0 ] && [ $(($1 % 100)) -ne 0 ] || [ $(($1 % 400)) -eq 0 ]
}

if isLeapYear "$1"; then

Ou utilisez le formulaire plus simple suggéré par @Wiimm:

isLeapYear() {
    (( !($1%4) && $1%100 || !($1%400) ))
}

En outre, pour les variables shell que vous utilisez, la casse minuscule ou mixte est préférable, pour éviter les conflits accidentels avec les nombreux noms de variables en majuscules qui ont des significations ou des fonctions spéciales.

1
Gordon Davisson 26 janv. 2019 à 21:18

Chaque commande définit un code de résultat. Si vous voulez forcer chaque calcul à se produire dans une fonction distincte, vous pouvez dire

divisibleBy4() {
    $((!("$1" % 4)))
}
notDivisibleBy100() {
     $(("$1" %100))
}
divisibleBy400() {
     $((!("$1" %400)))
}

(divisibleBy4 "$1" &&
 notDivisibleBy100 "$1" ||
 divisibleBy400 "$1") &&
echo "true" || echo "false"

Cependant, diviser votre logique en fonctions au niveau subatomique n'aide pas vraiment la lisibilité et la maintenabilité. Peut-être que si vous voulez rendre chaque partie raisonnablement autonome, utilisez des commentaires.

is_leap () {
    # Divisible by 4?
    (("$1" % 4 == 0)) || return
    # Not divisible by 100?
    (("$1" % 100 > 0)) && return
    # Divisible by 400?
    (("$1" % 400 == 0))
}

... Bien que les commentaires semblent plutôt superflus ici.

0
tripleee 27 janv. 2019 à 07:22

Vous voulez détecter une année bissextile! Une autre solution complète utilisant directement le mode mathématique:

a="$1"; (( !(a%4) && a%100 || !(a%400) )) && echo true || echo false

Ou comme si-alors-autre

a="$1";
if (( !(a%4) && a%100 || !(a%400) )); then
    echo true
else
    echo false
3
Wiimm 26 janv. 2019 à 19:50