Comment écrire un script shell pour attribuer des notes à des plages numériques?

19

Je veux créer un script qui vous demanderait un nombre compris entre 0 et 100, puis vous donnerait la note en fonction du nombre.

Je voudrais ça en bash.

PS3='Please enter your choice: '
(Something here)

do
case $
    "0-59")
        echo "F"
        ;;
    "60-69")
        echo "D"
        ;;
    "70-79")
        echo "C"
        ;;
    "Quit")
        break
        ;;
    *) echo invalid option;;
esac
done
Temple Pate
la source

Réponses:

20

Bref contre lisibilité: un terrain d'entente

Comme vous l'avez vu, ce problème admet des solutions qui sont modérément longues et quelque peu répétitives mais très lisibles ( réponses bash de terdon et AB ), ainsi que celles qui sont très courtes mais non intuitives et beaucoup moins auto-documentées ( python de Tim et réponses bash et réponse perl de glenn jackman ). Toutes ces approches sont précieuses.

Vous pouvez également résoudre ce problème avec du code au milieu du continuum entre compacité et lisibilité. Cette approche est presque aussi lisible que les solutions plus longues, avec une longueur plus proche des petites solutions ésotériques.

#!/usr/bin/env bash

read -erp 'Enter numeric grade (q to quit): '
case $REPLY in [qQ]) exit;; esac

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

for letter in F D C B A; do
    ((REPLY <= cutoffs[$letter])) && { echo $letter; exit; }
done
echo "Grade out of range."

Dans cette solution bash, j'ai inclus quelques lignes vides pour améliorer la lisibilité, mais vous pouvez les supprimer si vous le souhaitez encore plus court.

Les lignes vierges incluses, ce n'est en fait que légèrement plus court qu'une variante compactée et encore assez lisible de la solution bash d' AB . Ses principaux avantages par rapport à cette méthode sont:

  • C'est plus intuitif.
  • Il est plus facile de modifier les limites entre les notes (ou d'ajouter des notes supplémentaires).
  • Il accepte automatiquement les entrées avec des espaces de début et de fin (voir ci-dessous pour une explication du (( ))fonctionnement).

Ces trois avantages découlent du fait que cette méthode utilise l'entrée de l'utilisateur comme données numériques plutôt qu'en examinant manuellement ses chiffres constitutifs.

Comment ça fonctionne

  1. Lisez les entrées de l'utilisateur. Laissez-les utiliser les touches fléchées pour se déplacer dans le texte qu'ils ont entré ( -e) et ne pas interpréter \comme un caractère d'échappement ( -r).
    Ce script n'est pas une solution riche en fonctionnalités - voir ci-dessous pour un raffinement - mais ces fonctionnalités utiles ne font que deux caractères de plus. Je recommande de toujours utiliser -ravec read, sauf si vous savez que vous devez laisser l’utilisateur \s’échapper.
  2. Si l'utilisateur a écrit qou Q, quittez.
  3. Créez un tableau associatif ( ). Remplissez-le avec le grade numérique le plus élevé associé à chaque grade de lettre.declare -A
  4. Parcourez les notes des lettres du plus bas au plus élevé, en vérifiant si le nombre fourni par l'utilisateur est suffisamment bas pour tomber dans la plage numérique de chaque lettre.
    Avec (( ))l'évaluation arithmétique, les noms de variables n'ont pas besoin d'être développés avec $. (Dans la plupart des autres situations, si vous souhaitez utiliser la valeur d'une variable à la place de son nom, vous devez le faire .)
  5. S'il tombe dans la plage, imprimez la note et quittez .
    Par souci de concision, j'utilise le court-circuit et l' opérateur ( &&) plutôt qu'un if- then.
  6. Si la boucle se termine et qu'aucune plage n'a été mise en correspondance, supposez que le nombre entré est trop élevé (supérieur à 100) et informez l'utilisateur qu'il était hors plage.

Comment cela se comporte, avec une entrée étrange

Comme les autres solutions courtes publiées, ce script ne vérifie pas l'entrée avant de supposer qu'il s'agit d'un nombre. L'évaluation arithmétique ( (( ))) supprime automatiquement les espaces blancs de début et de fin, ce n'est donc pas un problème, mais:

  • Une entrée qui ne ressemble pas du tout à un nombre est interprétée comme 0.
  • Avec une entrée qui ressemble à un nombre (c'est-à-dire si elle commence par un chiffre) mais contient des caractères non valides, le script émet des erreurs.
  • L'entrée à plusieurs chiffres commençant par 0est interprétée comme étant en octal . Par exemple, le script vous dira que 77 est un C, tandis que 077 est un D. Bien que certains utilisateurs le veuillent, probablement pas et cela peut créer de la confusion.
  • Sur le plan positif, lorsqu'il reçoit une expression arithmétique, ce script la simplifie automatiquement et détermine le grade de lettre associé. Par exemple, il vous dira que 320/4 est un B.

Une version étendue et entièrement en vedette

Pour ces raisons, vous souhaiterez peut-être utiliser quelque chose comme ce script étendu, qui vérifie que l'entrée est bonne et inclut d'autres améliorations.

#!/usr/bin/env bash
shopt -s extglob

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

while read -erp 'Enter numeric grade (q to quit): '; do
    case $REPLY in  # allow leading/trailing spaces, but not octal (e.g. "03") 
        *( )@([1-9]*([0-9])|+(0))*( )) ;;
        *( )[qQ]?([uU][iI][tT])*( )) exit;;
        *) echo "I don't understand that number."; continue;;
    esac

    for letter in F D C B A; do
        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
    done
    echo "Grade out of range."
done

C'est toujours une solution assez compacte.

Quelles fonctionnalités cela ajoute-t-il?

Les points clés de ce script étendu sont:

  • Validation des entrées. Le script de terdon vérifie l'entrée avec , donc je montre une autre façon, qui sacrifie une certaine brièveté mais est plus robuste, permettant à l'utilisateur d'entrer dans les espaces de début et de fin et refusant d'autoriser une expression qui pourrait ou non être conçue comme octale (sauf si elle est nulle) .if [[ ! $response =~ ^[0-9]*$ ]] ...
  • J'ai utilisé caseavec l' extension globale au lieu de [[l' opérateur de =~ correspondance d'expressions régulières (comme dans la réponse de terdon ). Je l'ai fait pour montrer que (et comment) cela peut aussi être fait de cette façon. Globs et regexps sont deux façons de spécifier des modèles qui correspondent au texte, et l'une ou l'autre méthode convient à cette application.
  • Comme le script bash d'AB , j'ai enfermé le tout dans une boucle externe (sauf la création initiale du cutoffstableau). Il demande des chiffres et donne des notes de lettres correspondantes tant que l'entrée du terminal est disponible et que l'utilisateur ne lui a pas dit de quitter. À en juger par do... doneautour du code dans votre question, il semble que vous le vouliez.
  • Pour faciliter la fermeture, j'accepte toute variante insensible à la casse de qou quit.

Ce script utilise quelques constructions qui peuvent ne pas être familières aux novices; ils sont détaillés ci-dessous.

Explication: utilisation de continue

Lorsque je veux sauter le reste du corps de la whileboucle externe , j'utilise la continuecommande. Cela le ramène au sommet de la boucle, pour lire plus d'entrée et exécuter une autre itération.

La première fois que je fais cela, la seule boucle dans laquelle je suis est la whileboucle externe , donc je peux appeler continuesans argument. (Je suis dans une caseconstruction, mais cela n'affecte pas le fonctionnement de breakou continue.)

        *) echo "I don't understand that number."; continue;;

La deuxième fois, cependant, je suis dans une forboucle interne qui est elle-même imbriquée dans la whileboucle externe . Si j'utilisais continuesans argument, ce serait équivalent continue 1et continuerait la forboucle interne au lieu de la whileboucle externe .

        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }

Donc, dans ce cas, j'utilise continue 2pour faire bash find et continuer la deuxième boucle à la place.

Explication: caseétiquettes avec des globes

Je ne me casepour savoir quelle classe lettre bin un certain nombre tombe dans (comme dans la réponse bash AB ). Mais j'utilise casepour décider si l'entrée de l'utilisateur doit être prise en compte:

  • un numéro valide, *( )@([1-9]*([0-9])|+(0))*( )
  • la commande quit, *( )[qQ]?([uU][iI][tT])*( )
  • toute autre chose (et donc une entrée invalide), *

Ce sont des globes de coquille .

  • Chacun est suivi par un )qui ne correspond à aucune ouverture (, qui est casela syntaxe pour séparer un modèle des commandes qui s'exécutent lorsqu'il est mis en correspondance.
  • ;;est casela syntaxe utilisée pour indiquer la fin des commandes à exécuter pour une correspondance de cas particulier (et qu'aucun cas ultérieur ne doit être testé après leur exécution).

La globalisation du shell ordinaire permet de *faire correspondre zéro ou plusieurs caractères, de ?faire correspondre exactement un caractère et les classes / plages de caractères [ ]entre parenthèses. Mais j'utilise un globbing étendu , qui va au-delà. La globalisation étendue est activée par défaut lors d'une utilisation bashinteractive, mais elle est désactivée par défaut lors de l'exécution d'un script. La shopt -s extglobcommande en haut du script l'allume.

Explication: Globbing étendu

*( )@([1-9]*([0-9])|+(0))*( ), qui vérifie la saisie numérique , correspond à une séquence de:

  • Zéro ou plusieurs espaces ( *( )). La *( )construction correspond à zéro ou plus du motif entre parenthèses, qui n'est ici qu'un espace.
    Il existe en fait deux types d'espaces blancs horizontaux, des espaces et des tabulations, et il est souvent souhaitable de faire correspondre les tabulations également. Mais je ne m'inquiète pas à ce sujet ici, car ce script est écrit pour une entrée manuelle et interactive, et l' -eindicateur pour readactiver GNU readline. C'est ainsi que l'utilisateur peut se déplacer d'avant en arrière dans son texte avec les touches fléchées gauche et droite, mais cela a pour effet secondaire d'empêcher généralement la saisie littérale des onglets.
  • Une occurrence ( @( )) de soit ( |):
    • Un chiffre différent de zéro ( [1-9]) suivi de zéro ou plus ( *( )) de tout chiffre ( [0-9]).
    • Un ou plusieurs ( +( )) de 0.
  • Zéro ou plusieurs espaces ( *( )), encore une fois.

*( )[qQ]?([uU][iI][tT])*( ), qui vérifie la commande quit , correspond à une séquence de:

  • Zéro ou plusieurs espaces ( *( )).
  • qou Q( [qQ]).
  • Facultativement - c'est-à-dire zéro ou une occurrence ( ?( )) - de:
    • uou U( [uU]) suivi de iou I( [iI]) suivi de tou T( [tT]).
  • Zéro ou plusieurs espaces ( *( )), encore une fois.

Variante: validation de l'entrée avec une expression régulière étendue

Si vous préférez tester l'entrée de l'utilisateur par rapport à une expression régulière plutôt qu'à un glob de shell, vous préférerez peut-être utiliser cette version, qui fonctionne de la même façon, mais utilise [[et =~(comme dans la réponse de terdon ) au lieu de caseet un globbing étendu.

#!/usr/bin/env bash
shopt -s nocasematch

declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100

while read -erp 'Enter numeric grade (q to quit): '; do
    # allow leading/trailing spaces, but not octal (e.g., "03")
    if [[ ! $REPLY =~ ^\ *([1-9][0-9]*|0+)\ *$ ]]; then
        [[ $REPLY =~ ^\ *q(uit)?\ *$ ]] && exit
        echo "I don't understand that number."; continue
    fi

    for letter in F D C B A; do
        ((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
    done
    echo "Grade out of range."
done

Les avantages possibles de cette approche sont les suivants:

  • Dans ce cas particulier, la syntaxe est un peu plus simple, au moins dans le deuxième modèle, où je vérifie la commande quit. En effet, j'ai pu définir l' nocasematchoption shell, puis toutes les variantes de cas de qet quitont été couvertes automatiquement.

    C'est ce que fait la shopt -s nocasematchcommande. La shopt -s extglobcommande est omise car la globalisation n'est pas utilisée dans cette version.

  • Les compétences d'expression régulière sont plus courantes que la maîtrise des extglobs de bash.

Explication: Expressions régulières

En ce qui concerne les modèles spécifiés à droite de l' =~opérateur, voici comment ces expressions régulières fonctionnent.

^\ *([1-9][0-9]*|0+)\ *$, qui vérifie la saisie numérique , correspond à une séquence de:

  • Le début - c'est-à-dire le bord gauche - de la ligne ( ^).
  • Zéro ou plusieurs *espaces ( , postfixés appliqués). Un espace n'a généralement pas besoin d'être \échappé dans une expression régulière, mais cela est nécessaire avec [[pour éviter une erreur de syntaxe.
  • Une sous-chaîne ( ( )) qui est l'une ou l'autre ( |) de:
    • [1-9][0-9]*: un chiffre différent de zéro ( [1-9]) suivi de zéro ou plus ( *, suffixe appliqué) de tout chiffre ( [0-9]).
    • 0+: un ou plusieurs ( +, suffixe appliqué) de 0.
  • Zéro ou plusieurs espaces ( \ *), comme précédemment.
  • La fin - c'est-à-dire le bord droit - de la ligne ( $).

Contrairement aux caseétiquettes, qui correspondent à l'expression entière testée, =~renvoie true si une partie de son expression de gauche correspond au modèle donné comme expression de droite. C'est pourquoi les ancres ^et $, spécifiant le début et la fin de la ligne, sont nécessaires ici, et ne correspondent pas syntaxiquement à tout ce qui apparaît dans la méthode avec caseet extglobs.

Les parenthèses sont nécessaires pour faire ^et $se lier à la disjonction de [1-9][0-9]*et 0+. Sinon, ce serait la disjonction de ^[1-9][0-9]*et 0+$, et correspondrait à toute entrée commençant par un chiffre différent de zéro ou se terminant par un 0(ou les deux, qui pourrait toujours inclure des chiffres non intermédiaires).

^\ *q(uit)?\ *$, qui vérifie la commande quit , correspond à une séquence de:

  • Le début de la ligne ( ^).
  • Zéro ou plusieurs espaces ( \ *voir l'explication ci-dessus).
  • La lettre q. Ou Q, puisque shopt nocasematchest activé.
  • Facultativement - c'est-à-dire zéro ou une occurrence (suffixe ?) - de la sous-chaîne ( ( )):
    • u, suivi de i, suivi de t. Ou, puisque shopt nocasematchest activé upeut être U; indépendamment, ipeut être I; et indépendamment, tpeut être T. (Autrement dit, les possibilités ne sont pas limitées à uitet UIT.)
  • Zéro ou plusieurs espaces à nouveau ( \ *).
  • La fin de la ligne ( $).
Eliah Kagan
la source
3
dites-moi la vérité .. combien de temps cela a pris? ;)
heemayl
4
@heemayl Je ne suis pas totalement sûr, car je l'ai écrit en plusieurs petites parties tout au long de la journée (suivi d'une lecture complète et de modifications, juste avant de poster). Je suis à peu près sûr que cela a fini par prendre plus de temps que je ne l'aurais pensé quand j'ai commencé, si j'avais pensé au temps que cela allait prendre. :)
Eliah Kagan
6
écrivez de plus en plus, j'ai besoin d'un livre de vos réponses.
Grijesh Chauhan
TL; DR mais m'a quand même fait rire!
Fabby
tout, du titre à l'explication, est bon. Je l'ai compris du premier coup mais je l'ai relu juste parce que je voulais
Sumeet Deshmukh
23

Vous avez déjà l'idée de base. Si vous voulez coder cela bash(ce qui est un choix raisonnable car c'est le shell par défaut sur Ubuntu et la plupart des autres Linux), vous ne pouvez pas l'utiliser casecar il ne comprend pas les plages. À la place, vous pouvez utiliser if/ else:

#!/usr/bin/env bash

read -p "Please enter your choice: " response

## If the response given did not consist entirely of digits
if [[ ! $response =~ ^[0-9]*$ ]]
then
    ## If it was Quit or quit, exit
    [[ $response =~ [Qq]uit ]] && exit
    ## If it wasn't quit or Quit but wasn't a number either,
    ## print an error message and quit.
    echo "Please enter a number between 0 and 100 or \"quit\" to exit" && exit
fi
## Process the other choices
if [ $response -le 59 ]
then
    echo "F"
elif [ $response -le 69 ]
then
    echo "D"
elif  [ $response -le 79 ]
then
    echo "C"
elif  [ $response -le 89 ]
then
    echo "B"
elif [ $response -le 100 ]
then
    echo "A"
elif [ $response -gt 100 ]
then
    echo "Please enter a number between 0 and 100"
     exit
fi
terdon
la source
4
Un tas de ces -getests peuvent être éliminés, probablement, puisque vous utilisez elif. Et pas d'amour pour (( $response < X ))?
muru
2
@muru true, merci. J'étais coincé en pensant à des plages de nombres, mais il n'y avait aucune raison de le faire. Quant à (( $response < X )), bien sûr, mais je trouve cela plus clair et l'OP est évidemment nouveau pour les scripts bash.
terdon
12
#!/bin/bash

while true
do
  read -p "Please enter your choice: " choice

  case "$choice"
   in
      [0-9]|[1-5][0-9])
          echo "F"
          ;;
      6[0-9])
          echo "D"
          ;;
      7[0-9])
          echo "C"
          ;;
      8[0-9])
          echo "B"
          ;;
      9[0-9]|100)
          echo "A"
          ;;
      [Qq])
          exit 0
          ;;
      *) echo "Only numbers between 0..100, q for quit"
          ;;
  esac
done

et une version plus compacte (Thx @EliahKagan ):

#!/usr/bin/env bash

while read -erp 'Enter numeric grade (q to quit): '; do
    case $REPLY in
        [0-9]|[1-5][0-9])   echo F ;;
        6[0-9])             echo D ;;
        7[0-9])             echo C ;;
        8[0-9])             echo B ;;
        9[0-9]|100)         echo A ;;

        [Qq])               exit ;;
        *)                  echo 'Only numbers between 0..100, q for quit' ;;
    esac
done
UN B
la source
1
Ce sont des plages de caractères, sûrement? c'est-à-dire [0-59]signifie n'importe quel caractère de 0,1,2,3,4,5 ou 9 et ainsi de suite. Je ne vois pas comment cela peut fonctionner pour les valeurs numériques .
steeldriver
3
Vous n'avez pas besoin d'être FGITW tout le temps. Prenez votre temps, écrivez de bonnes réponses. Regardez comment fonctionnent Terdon ou Eliah Kagan.
muru
@AB J'ai remarqué que cette solution peut être raccourcie, principalement par des changements stylistiques, tout en restant assez lisible. La brièveté est rarement la considération la plus importante, donc je ne pense pas que vous devriez changer ce que vous avez de cette façon. Mais comme la forme plus compacte ne prend pas beaucoup de place, vous pourriez envisager de la montrer également, au cas où certains lecteurs souhaiteraient un script plus court qui fonctionne de la même manière. (Si vous le souhaitez, n'hésitez pas à utiliser ma version abrégée ou toute variation à ce sujet.)
Eliah Kagan
9

Toutes les installations Ubuntu ont Python, voici donc un script python one liner. Si vous avez besoin qu'il soit en bash, j'ai également écrit l'équivalent en tant que script shell .

print (chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1]))))

Pour l'exécuter, enregistrez-le dans un fichier (par exemple grade.py) puis exécutez-le dans le terminal avec ceci:

python grade.py

Voici ce que vous verrez:

Enter the number: 65
E

Comment cela marche-t-il?

  1. Prenez l'entrée - 65.
  2. Ajoutez un 0 au début - 065.
  3. Retirez le dernier caractère - 06.
  4. 75 soustrayez ce nombre - 70.
  5. Convertir en lettre (A est 65, B est 66) - E.
  6. Imprimez-le - E.

Mes pronoms sont He / Him

Tim
la source
J'aime votre idée. +1
AB
Ne pas utiliser input(), il appellera eval(), utilisez à la place raw_input().. aussi votre classement n'est pas correct comme 90+l'imprimera la note .. Butilisez chr(74 - max(4, num))....
heemayl
well..your solution est agréable et travaillera en python2 also..just changer l' input()à raw_input()pour python2..thats il ..
heemayl
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
heemayl
Ensuite , vous devez changer votre too..your de code original du code modifed tel qu'il est actuellement ne va pas bien que python3ne pas raw_input().. je suggère raw_input()pour votre une initiale que vous avez dit à l' exécuter en utilisant python2..
heemayl
6

Voici ma solution bash semi- ésotérique, qui remplit un tableau avec 101 entrées, puis vérifie les entrées utilisateur par rapport à elles. Même pour une utilisation dans le monde réel, c'est raisonnable - si vous aviez besoin d'excellentes performances, vous n'utiliseriez pas bash, et une centaine (ou plus) d'affectations est toujours rapide. Mais cela cesserait d'être raisonnable s'il était étendu à une gamme beaucoup plus large (comme un million).

#!/usr/bin/env bash
p(){ for i in `seq $2 $3`; do g[$i]=$1; done; }
p A 90 100; p B 80 89; p C 70 79; p D 60 69; p F 0 59
while read -r n && [[ ! $n =~ ^[qQ] ]]; do echo ${g[$n]}; done

Avantages:

  • Ce n'est pas vraiment ésotérique.Bien que ce soit plus long que les solutions les plus courtes, et pas tout à fait aussi auto-documenté que les solutions plus longues ... il est raisonnablement auto-documenté , tout en étant décidément encore petit.
  • Il permet une modification facile pour changer les gammes de notes ou ajouter / supprimer des notes.
  • Il fonctionne en boucle et les départs volontaires sur q, quitou quoi que ce soit à partir de q/Q .
  • Répertorie les notes supérieures en premier, pour vous aider à penser positif. :)
  • Hmm, cela fait le travail, continue de faire sens même après l'avoir regardé, et possède les caractéristiques essentielles. Vous pourriez en fait l'utiliser!

Désavantages:

  • Cela vous donne un F lorsque vous entrez une entrée non numérique ... mais ce n'est pas vraiment si mal, n'est-ce pas? Si vous donnez un non-nombre où un nombre est nécessaire, peut-être méritez-vous un F!
  • L'entrée ambiguë, éventuellement octale, est traitée comme octale (puisqu'il gs'agit d'un tableau indexé unidimensionnel ). Comme le dit le vieil adage, "Ce n'est pas un bug, c'est une fonctionnalité!" Eh bien, peut-être.
  • Une entrée hors plage ou non un nombre entraîne l'impression d'une ligne vide. Cependant, il n'y a rien de mal à cela: il vous indique quelle note correspond à votre saisie, et pour une mauvaise saisie, il n'y en a pas.
  • Mettez un nombre négatif, et ça ... eh bien, appelez ça un œuf de Pâques .
  • Toujours beaucoup plus long que la solution python de Tim . Ouais, je ne peux pas vraiment faire tourner ça pour avoir l'air d'un avantage.

Un peu cool, hein? (Eh bien, je pense que oui.)

Comment ça fonctionne

  1. La pfonction p opulates un tableau indexé numériquement gde g rades, à des indices allant de son premier argument à la seconde, la valeur (lettre) donnée dans son troisième argument.
  2. p est appelé pour chaque grade de lettre, pour définir sa plage numérique.
  3. Continuez à lire les entrées utilisateur tant qu'elles sont disponibles et ne commencent pas par q(ou Q), vérifiez le gtableau pour lequel le grade de lettre correspond au nombre entré et imprimez cette lettre.
Eliah Kagan
la source
Et ce conditionnel? [[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
Helio
6

Après l' avoir fait en Python 2 , j'ai décidé de le faire en bash.

#! /bin/bash

read -p "Enter the number: " i
i=0$i
x=$((10#${i::-1}))
printf "\x$(printf %x $((11-($x>5?$x:5)+64)))\n"

Pour l'exécuter, enregistrez-le dans un fichier (par exemple grade.sh), rendez-le exécutable avec chmod +x grade.shpuis exécutez avec ./grade.sh.

Voici ce que vous verrez:

Enter the number: 65
E

Comment cela marche-t-il?

  1. Prenez l'entrée - 65.
  2. Ajoutez un 0 au début - 065(et le 10#conserve la base 10).
  3. Retirez le dernier caractère - 06.
  4. 75 soustrayez ce nombre - 70.
  5. Convertir en lettre (A est 65, B est 66) - E.
  6. Imprimez le - E.

Mes pronoms sont He / Him

Tim
la source
Très intelligent, bien fait
kos
@kos merci :) Je doute que cela fonctionne pour l'OP car ses gammes ne sont probablement pas celles qu'il a publiées. Je m'attends à ce que ce soit pour la simplicité.
Tim
5

Et voici ma version awk:

awk '{
  if($_ <= 100 && $_ >= 0) {
      sub(/^([0-9]|[1-5][0-9])$/, "F", $_);
      sub(/^(6[0-9])$/, "D", $_);
      sub(/^(7[0-9])$/, "C", $_);
      sub(/^(8[0-9])$/, "B", $_);
      sub(/^(9[0-9]|100)$/, "A", $_);
      print
    }
    else {
      print "Only numbers between 0..100"
    }
}' -

ou en une ligne:

awk '{if($_ <= 100 && $_ >= 0) { sub(/^([0-9]|[1-5][0-9])$/, "F", $_); sub(/^(6[0-9])$/, "D", $_); sub(/^(7[0-9])$/, "C", $_); sub(/^(8[0-9])$/, "B", $_);sub(/^(9[0-9]|100)$/, "A", $_);   print} else { print "Only numbers between 0..100"}}' -
UN B
la source
4

Voici une autre réponse "ésotérique"

perl -E '
    print "number: "; 
    $n = <>; 
    say qw/A A B C D E F F F F F/[11-($n+1)/10]
       if $n=~/^\s*\d/ and 0<=$n and $n<=100
'

Explication

  • perl -E: le -E, comme -e, permet de passer un script comme argument de ligne de commande. C'est une façon d'exécuter Perl one-liners. Contrairement à -e, -Eactive également toutes les fonctionnalités optionnelles (comme say, qui est fondamentalement un printavec une nouvelle ligne de fin.).
  • print "number: "; : invite l'utilisateur à saisir un numéro.
  • $n = <>;: enregistrez ce numéro sous $n.

Le bit suivant doit être décomposé un peu. qw/string/évalue à une liste faite en coupant stringà l'espace blanc. Donc, qw/A A B C D E F F F F F/est en fait cette liste:

0 : A
1 : A
2 : B
3 : C
4 : D
5 : E
6 : F
7 : F
8 : F
9 : F
10 : F

Par conséquent, say qw/A A B C D E F F F F F/[11-($n+1)/10]est équivalent à

my @F=("A","A","B","C","D","E","F","F","F","F","F");
print "$F[11-($n+1)/10]\n"

Maintenant, Perl permet d'utiliser des indices négatifs pour récupérer les éléments en comptant à partir de la fin du tableau. Par exemple,$arrray[-1] affichera le dernier élément du tableau. De plus, les indices de tableau à virgule flottante (par exemple 10,7) sont automatiquement tronqués au prochain entier inférieur (10,7 ou 10,3 ou tout ce qui devient 10.)

Le résultat de tout cela est que l'index est 11-($n+1)/10toujours évalué à l'élément (grade) approprié du tableau.

glenn jackman
la source
4
Les réponses ésotériques sont toutes agréables, mais veuillez inclure une explication.
muru
1

Bien que vous ayez demandé une solution bash, je pense qu'en python, cela peut être fait de manière élégante et courte. Couvrant à la fois les erreurs de gestion en cas de saisie incorrecte et la "conversion" d'un nombre compris entre 0 et 100 en lettres de A à F (ou tout autre):

#!/usr/bin/env python3
try:
    n = int(input("number: ")); n = n if n>0 else ""
    print("FEDCBA"[[n>=f for f in [50,60,70,80,90,101]].count(True)])
except:
    print("invalid input")

Explication

  1. Nous devons d'abord obtenir le numéro de l'utilisateur:

    n = int(input("number: "))
  2. Nous testons ce numéro pour être valide pour un certain nombre de conditions:

    n>=50, n>=60, n>=70, n>=80, n>=90

    Pour chacun de ces tests, le résultat sera soit Falseou True. Par conséquent (en compressant un peu le code):

    [n>=f for f in [50,60,70,80,90]].count(True)]

    produira un chiffre de 0à5

  3. Par la suite, nous pouvons utiliser cette figure comme index pour une chaîne, pour produire un caractère en sortie, par exemple

    "ABCDEF"[3] 

    affichera "D" (puisque le premier caractère = "A")

  4. L'additionnel 101à la liste est de générer une erreur (Index-) au cas où le nombre dépasse 100, puisqu'il "ABCDEF"[6]n'existe pas. Il en va de même pour n = n if n>=0 else ""ce qui créera une erreur (Value-) si un nombre inférieur à 0 est entré
    Dans ces cas, ainsi que si l'entrée n'est pas un chiffre, le résultat sera:

    invalid input

Les tests:

number: 10
F

number: 50
E

number: 60
D

number: 70
C

number: 80
B

number: 90
A

number: 110
invalid input

number: -10
invalid input

number: Monkey
invalid input
Jacob Vlijm
la source