Как написать сценарий оболочки для присвоения буквенных оценок числовым диапазонам?

19

Я хочу сделать сценарий, который будет запрашивать у вас число от 0 до 100, а затем давать вам оценку на основе числа.

Я хотел бы это в Баш.

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
Храмовая Паштет
источник

Ответы:

20

Краткость и удобочитаемость: золотая середина

Как вы видели, эта проблема допускает решения, которые являются умеренно длинными и несколько повторяющимися, но очень удобочитаемыми ( ответы Терда и А. Б. на bash), а также очень короткими, но не интуитивными и гораздо менее самодокументируемыми ( Python Тима). и Bash ответы и Perl ответ Гленна Джекмана ). Все эти подходы ценны.

Вы также можете решить эту проблему с помощью кода в середине континуума между компактностью и удобочитаемостью. Этот подход почти так же читабелен, как и более длинные решения, с длиной, близкой к маленьким, эзотерическим решениям.

#!/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."

В этом решении bash я добавил несколько пустых строк для улучшения читабельности, но вы можете удалить их, если хотите, чтобы они были еще короче.

Пустые строки включены, это на самом деле лишь немного короче, чем компактный, все еще довольно читаемый вариант решения bash от AB . Его основные преимущества перед этим методом:

  • Это более интуитивно понятно.
  • Проще изменить границы между оценками (или добавить дополнительные оценки).
  • Он автоматически принимает ввод с начальными и конечными пробелами (объяснение того, как (( ))работает, см. Ниже ).

Все три из этих преимуществ возникают из-за того, что этот метод использует ввод пользователя в качестве числовых данных, а не путем ручного изучения составляющих его цифр.

Как это устроено

  1. Прочитать ввод от пользователя. Позвольте им использовать клавиши со стрелками для перемещения по тексту, который они ввели ( -e), и не интерпретировать \как escape-символ ( -r).
    Этот скрипт не является многофункциональным решением - уточнение приведено ниже - но эти полезные функции делают его на два символа длиннее. Я рекомендую всегда использовать -rс read, если только вы не знаете, что нужно разрешить пользователю \сбегать.
  2. Если пользователь написал qили Q, выйти.
  3. Создать ассоциативный массив ( declare -A). Заполните его наивысшей числовой оценкой, связанной с каждой буквенной оценкой.
  4. Перебирайте буквенные оценки от самых низких до самых высоких, проверяя, достаточно ли низкое число, предоставленное пользователем, чтобы попасть в числовой диапазон каждой буквенной оценки.
    При (( ))арифметической оценке имена переменных не нужно расширять $. (В большинстве других ситуаций, если вы хотите использовать значение переменной вместо ее имени, вы должны сделать это .)
  5. Если он попадает в диапазон, выведите оценку и выйдите .
    Для краткости я использую короткое замыкание и operator ( &&), а не if- then.
  6. Если цикл завершается и диапазон не соответствует, предположите, что введенное число слишком велико (более 100) и сообщите пользователю, что оно вышло за пределы диапазона.

Как это ведет себя со странным вводом

Как и в других опубликованных кратких решениях, этот сценарий не проверяет ввод перед тем, как предположить, что это число. Арифметическая оценка ( (( ))) автоматически удаляет начальные и конечные пробелы, так что это не проблема, но:

  • Ввод, который совсем не похож на число, интерпретируется как 0.
  • В случае ввода, которое выглядит как число (т. Е. Если оно начинается с цифры), но содержит недопустимые символы, скрипт выдает ошибки.
  • Мульти-значный вход начиная с 0будет интерпретироваться как в восьмеричной системе . Например, скрипт скажет вам, что 77 - это C, а 077 - это D. Хотя некоторые пользователи могут этого хотеть, скорее всего, нет, и это может вызвать путаницу.
  • С другой стороны, когда задано арифметическое выражение, этот скрипт автоматически упрощает его и определяет соответствующую буквенную оценку. Например, он скажет вам, что 320/4 - это B.

Расширенная, полнофункциональная версия

По этим причинам вы можете захотеть использовать что-то вроде этого расширенного скрипта, который проверяет правильность ввода и включает некоторые другие улучшения.

#!/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

Это все еще довольно компактное решение.

Какие функции это добавляет?

Ключевые пункты этого расширенного сценария:

  • Подтверждение ввода. Скрипт terdon проверяет ввод с помощью , поэтому я показываю другой способ, который жертвует некоторой краткостью, но является более надежным, позволяя пользователю вводить начальные и конечные пробелы и отказываясь разрешить выражение, которое может или не может быть задано как восьмеричное (если оно не равно нулю) ,if [[ ! $response =~ ^[0-9]*$ ]] ...
  • Я использовал caseс расширенной подстановкой вместо [[с =~ регулярными выражениями оператора (как в ответе terdon в ). Я сделал это, чтобы показать, что (и как) это тоже можно сделать таким образом. Globs и regexps - это два способа задания шаблонов, которые соответствуют тексту, и любой метод подходит для этого приложения.
  • Как и сценарий bash AB , я заключил все это во внешний цикл (за исключением первоначального создания cutoffsмассива). Он запрашивает цифры и выставляет соответствующие буквенные оценки, пока имеется доступ к терминалу и пользователь не велел ему выйти. Судя по do... doneвокруг кода в вашем вопросе, похоже, что вы этого хотите.
  • Чтобы облегчить выход, я принимаю любой вариант qили без учета регистра quit.

Этот скрипт использует несколько конструкций, которые могут быть незнакомы новичкам; они подробно описаны ниже.

Пояснение: использование continue

Когда я хочу пропустить остальную часть тела внешнего whileцикла, я использую continueкоманду. Это возвращает его к началу цикла, чтобы прочитать больше входных данных и выполнить еще одну итерацию.

В первый раз, когда я делаю это, единственный цикл, в котором я нахожусь, это внешний whileцикл, поэтому я могу вызывать continueбез аргументов. (Я нахожусь в caseконструкции, но это не влияет на работу breakили continue.)

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

Второй раз, однако, я нахожусь во внутреннем forцикле, который сам вложен во внешний whileцикл. Если бы я использовал continueбез аргумента, это было бы эквивалентно continue 1и продолжило бы внутренний forцикл вместо внешнего whileцикла.

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

Поэтому в этом случае я использую continue 2bash для поиска и продолжения второго цикла.

Пояснение: caseЯрлыки с шариками

Я не использую , caseчтобы выяснить , какая буква класса бен число попадает (как в Баш ответ АБ ). Но я использую, caseчтобы решить, следует ли учитывать ввод пользователя:

  • действительный номер, *( )@([1-9]*([0-9])|+(0))*( )
  • команда выхода, *( )[qQ]?([uU][iI][tT])*( )
  • что-нибудь еще (и, следовательно, неверный ввод), *

Это ракушки .

  • За каждым следует a, )которому не соответствует ни одно открытие (, то есть caseсинтаксис для отделения шаблона от команд, запускаемых при его сопоставлении.
  • ;;caseСинтаксис is для указания конца команд, запускаемых для совпадения конкретного случая (и что последующие случаи не должны проверяться после их запуска).

Обычная глобализация оболочки обеспечивает *совпадение с нулем или более символов, ?чтобы точно соответствовать одному символу, а также классы / диапазоны символов в [ ]скобках. Но я использую расширенную глобализацию , которая выходит за рамки этого. При использовании в bashинтерактивном режиме расширенная глобализация включена по умолчанию , но по умолчанию она отключена при запуске сценария. Команда shopt -s extglobв верхней части скрипта включает его.

Пояснение: расширенная глобализация

*( )@([1-9]*([0-9])|+(0))*( ), который проверяет числовой ввод , соответствует последовательности:

  • Ноль или более пробелов ( *( )). В *( )конструкт соответствует нулю или более шаблона в скобках, что здесь есть только пространство.
    На самом деле есть два вида горизонтальных пробелов, пробелов и табуляции, и часто желательно также сопоставлять табуляции. Но я не беспокоюсь об этом здесь, потому что этот сценарий написан для ручного, интерактивного ввода и -eфлага для включения readGNU readline. Это позволяет пользователю перемещаться по тексту назад и вперед с помощью клавиш со стрелками влево и вправо, но это имеет побочный эффект, как правило, предотвращает буквальный ввод вкладок.
  • Одно вхождение ( @( )) любого ( |):
    • Ненулевая цифра ( [1-9]), за которой следует ноль или более ( *( )) любой цифры ( [0-9]).
    • Один или несколько ( +( )) из 0.
  • Ноль или более пробелов ( *( )), снова.

*( )[qQ]?([uU][iI][tT])*( ), который проверяет команду quit , соответствует последовательности:

  • Ноль или более пробелов ( *( )).
  • qили Q( [qQ]).
  • Необязательно - то есть ноль или одно вхождение ( ?( )) - из:
    • uили U( [uU]) с последующим iили I( [iI]) с последующим tили T( [tT]).
  • Ноль или более пробелов ( *( )), снова.

Вариант: проверка ввода с расширенным регулярным выражением

Если вы предпочитаете проверять вводимые пользователем данные вместо регулярного выражения, а не глобуса оболочки, вы можете предпочесть использовать эту версию, которая работает так же, но использует [[и =~(как в ответе Тердона ) вместо caseрасширенного глобирования.

#!/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

Возможные преимущества этого подхода заключаются в том, что:

  • В этом конкретном случае синтаксис немного проще, по крайней мере, во втором шаблоне, где я проверяю команду quit. Это потому, что я смог установить параметр nocasematchоболочки, а затем все варианты вариантов qи quitбыли покрыты автоматически.

    Это то, что shopt -s nocasematchделает команда. Команда shopt -s extglobне указана, поскольку в этой версии не используется глобализация.

  • Навыки регулярного выражения более распространены, чем умение использовать экглобы bash.

Пояснение: Регулярные выражения

Что касается шаблонов, указанных справа от =~оператора, то вот как работают эти регулярные выражения.

^\ *([1-9][0-9]*|0+)\ *$, который проверяет числовой ввод , соответствует последовательности:

  • Начало - т. Е. Левый край - линии ( ^).
  • Ноль или более (с *применением постфикса) пробелов. Пробел обычно не нужно \экранировать в регулярном выражении, но это необходимо [[для предотвращения синтаксической ошибки.
  • Подстрока ( ( )), которая является одним или другим ( |) из:
    • [1-9][0-9]*: ненулевая цифра ( [1-9]), за которой следует ноль или более ( *примененный постфикс) любой цифры ( [0-9]).
    • 0+: один или несколько ( +примененный постфикс) из 0.
  • Ноль или более пробелов ( \ *), как и раньше.
  • Конец - то есть правый край - линии ( $).

В отличие от caseметок, которые соответствуют всему тестируемому выражению, =~возвращает true, если какая-либо часть его левого выражения совпадает с шаблоном, заданным как его правое выражение. Вот почему ^и $якорь, указав начало и конец строки, которые необходимы здесь, и не соответствует синтаксический ни к чему появляющемуся в методе с caseи extglobs.

Скобки необходимы, чтобы сделать ^и $связать с дизъюнкцией [1-9][0-9]*и 0+. В противном случае это будет дизъюнкция ^[1-9][0-9]*и 0+$, и совпадение с любым вводом, начинающимся с ненулевой цифры или заканчивающимся на 0(или оба, которые могут все еще включать нецифровые цифры между ними).

^\ *q(uit)?\ *$, который проверяет команду quit , соответствует последовательности:

  • Начало строки ( ^).
  • Ноль или более пробелов ( \ *см. Объяснение выше).
  • Письмо q. Или Q, так shopt nocasematchкак включен.
  • Опционально - то есть ноль или одно вхождение (постфикс ?) - подстроки ( ( )):
    • u, сопровождаемый i, сопровождаемый t. Или, так shopt nocasematchкак включен uможет быть U; независимо, iможет быть I; и независимо, tможет быть T. (То есть возможности не ограничиваются uitа UIT.)
  • Ноль или более пробелов снова ( \ *).
  • Конец строки ( $).
Элия ​​Каган
источник
3
скажи мне правду .. сколько времени это заняло? ;)
Heemayl
4
@heemayl Я не совсем уверен, так как я написал это во многих маленьких частях в течение дня (сопровождаемый полным чтением и редактированием, непосредственно перед отправкой). Я почти уверен, что это заняло больше времени, чем я думал, когда начал, хотя, если бы я думал о том, сколько времени это займет. :)
Элия ​​Каган
6
пиши все больше и больше, мне нужна книга твоих ответов.
Грижеш Чаухан
TL; DR, но я все равно рассмеялся!
Fabby
все от названия до объяснения хорошо. Я понял это с первого
Сумеит Дешмух
23

У вас уже есть основная идея. Если вы хотите закодировать это bash(что является разумным выбором, поскольку это оболочка по умолчанию в Ubuntu и большинстве других Linux), вы не можете использовать ее, caseпотому что она не понимает диапазоны. Вместо этого вы можете использовать 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
источник
4
Куча этих -geтестов может быть исключена, по-видимому, так как вы используете elif. А любви нет (( $response < X ))?
Муру
2
@ Муру правда, спасибо. Я застрял, думая о числовых диапазонах, но не было никаких причин для этого. Что касается (( $response < X )), конечно, но я нахожу это более понятным, и OP, очевидно, является новым для сценариев bash.
тердон
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

и более компактная версия (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
AB
источник
1
Это диапазоны символов, конечно? т.е. [0-59]означает любой символ от 0,1,2,3,4,5 или 9 и так далее. Я не понимаю, как это может работать для числовых значений.
Steeldriver
3
Вам не нужно быть FGITW все время. Не торопитесь, пишите хорошие ответы. Посмотрите, как работают Тердон или Элия Каган.
Муру
@AB Я заметил, что это решение может быть сокращено, в основном за счет стилистических изменений, при этом оставаясь вполне читабельным. Краткость редко является наиболее важным фактором, поэтому я не думаю, что вы должны изменить то, что у вас есть, таким образом. Но поскольку более компактная форма не занимает много места, вы можете также рассмотреть возможность ее показа на тот случай, если некоторые читатели захотят более короткий сценарий, который работает аналогичным образом. (Если хотите, пожалуйста, не стесняйтесь использовать мою сокращенную версию или любую другую версию.)
Элия ​​Каган,
9

Все установки Ubuntu имеют Python, так что здесь один скрипт Python . Если вам нужно, чтобы он был в bash, я также написал эквивалент в виде сценария оболочки .

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

Для запуска сохраните его в файле (например grade.py), а затем запустите в терминале с помощью этого:

python grade.py

Вот что вы увидите:

Enter the number: 65
E

Как это работает?

  1. Принять вход - 65.
  2. Добавить 0 в начало - 065.
  3. Удалить последний символ - 06.
  4. 75 вычтите это число 70.
  5. Преобразовать в букву (A 65, B 66) - E.
  6. Распечатайте это E.

Мои местоимения Он / Он

Тим
источник
Мне нравится твоя идея. +1
AB
Не используйте input(), это вызовет eval(), используйте raw_input()вместо этого .. Также ваша оценка не правильна, как 90+будет печатать оценку B.. используйте chr(74 - max(4, num))....
heemayl
well..your решение красиво и будет работать в python2 also..just изменения input()к raw_input()для python2..thats это ..
heemayl
print chr(75-max(5,int('0'+raw_input('Enter the number: ')[:-1])))
Heemayl
Затем вам нужно изменить исходный код тоже. Ваш модифицированный код в его текущем состоянии является неправильным, хотя python3и не имеет raw_input().. Я предложил raw_input()для исходного кода, как вы сказали, чтобы запустить его с помощью python2..
heemayl
6

Вот мой полу -esoteric раствор Баш, который заполняет массив с 101 записей , а затем проверяет ввод пользователя по отношению к ним. Даже для реального использования это разумно - если вам нужна отличная производительность, вы не будете использовать bash, и сотня (или около того) заданий по-прежнему быстрая. Но это перестало бы быть разумным, если бы оно расширилось до гораздо большего диапазона (например, до миллиона).

#!/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

Преимущества:

  • Это не совсем так эзотерично. Хотя он длиннее самых коротких решений и не так самодокументирован, как более длинные решения ... он достаточно самодокументирован , но все же решительно на крошечной стороне.
  • Это позволяет легко модифицировать, чтобы изменить диапазоны оценок или добавить / удалить оценки.
  • Он работает в цикле и уйдет в отставку q, quitили что - либо , начиная с q/ Q.
  • Сначала перечислите более высокие оценки, чтобы помочь вам думать о хорошем. :)
  • Хм, это делает работу, имеет смысл даже после того, как вы посмотрите на нее, и имеет важные функции. Вы могли бы на самом деле использовать это!

Недостатки:

  • Это дает вам F, когда вы вводите нецифровый ввод ... но это не так уж и плохо, не так ли? Если вы дадите номер, где номер нужен, возможно, вы заслуживаете F!
  • Неоднозначный, возможно восьмеричный ввод рассматривается как восьмеричный (так gкак это одномерный индексированный массив ). Как гласит старая поговорка: «Это не ошибка, это особенность!» Что же, может быть.
  • Ввод, выходящий за пределы диапазона или не являющийся числом, приводит к печати пустой строки. Хотя в этом нет ничего плохого: он говорит вам, какая буквенная оценка соответствует вашему вводу, а для неправильного - нет.
  • Введите отрицательное число, и это ... ну, назовите это пасхальным яйцом .
  • Все еще значительно дольше, чем решение Тима Python . Да, я не могу раскрутить это, чтобы казаться преимуществом.

Вроде круто, а? (Ну, я так думаю.)

Как это устроено

  1. pФункция р opulates численно индексированный массив gиз г Rades, на индексы в диапазоне от первого аргумента ко второму ее, со значением (буква) , приведенной в его третьим аргументом.
  2. p вызывается для каждой буквенной оценки, чтобы определить ее числовой диапазон.
  3. Продолжайте читать вводимые пользователем данные, пока они доступны и не начинаются с q(или Q), проверяя gмассив, для которого оценка буквы соответствует введенному числу, и печатая эту букву.
Элия ​​Каган
источник
Как насчет этого условного? [[ $n =~ ^(0|[1-9]+[0-9]*)$ ]]
Гелио
6

После того, как сделать это в Python 2 , я решил сделать это в Баш.

#! /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"

Для запуска сохраните его в файле (например, grade.sh), сделайте его исполняемым с, chmod +x grade.shа затем запустите с ./grade.sh.

Вот что вы увидите:

Enter the number: 65
E

Как это работает?

  1. Принять вход - 65.
  2. Добавьте 0 к началу - 06510#держите его основанием 10).
  3. Удалить последний символ - 06.
  4. 75 вычтите это число 70.
  5. Преобразовать в букву (A 65, B 66) - E.
  6. Распечатайте это E.

Мои местоимения Он / Он

Тим
источник
Очень умно, хорошо сделано
Кос
@kos спасибо :) Я сомневаюсь, что это будет работать для OP, потому что его диапазоны, вероятно, не то, что он отправил. Я ожидаю, что это для простоты.
Тим
5

И вот моя версия 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"
    }
}' -

или как однострочник:

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"}}' -
AB
источник
4

Вот еще один «эзотерический» ответ

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
'

объяснение

  • perl -E: -Eвроде бы -eпозволяет передавать скрипт в качестве аргумента командной строки. Это способ запуска однострочников Perl. В отличие от -e, -Eтакже включает все дополнительные функции (такие как say, в основном, printс завершающим переводом строки).
  • print "number: "; : предложить пользователю ввести номер.
  • $n = <>;: сохранить этот номер как $n.

Следующий бит нужно немного разбить. qw/string/оценивает список, сделанный, ломая stringв пробеле. Итак, qw/A A B C D E F F F F F/на самом деле этот список:

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

Следовательно, say qw/A A B C D E F F F F F/[11-($n+1)/10]эквивалентно

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

Теперь Perl позволяет использовать отрицательные индексы для извлечения элементов, считая с конца массива. Например, $arrray[-1]будет напечатан последний элемент массива. Кроме того, индексы массива с плавающей запятой (например, 10,7) автоматически усекаются до следующего более низкого целого числа (10,7, или 10,3, или все, что становится 10).

Результатом всего этого является то, что индекс 11-($n+1)/10всегда оценивается в соответствующий элемент (класс) массива.

Гленн Джекман
источник
4
Все эзотерические ответы хороши, но, пожалуйста, включите объяснение.
Муру
1

Хотя вы и просили решение для bash, я думаю, что в python это можно сделать элегантным и коротким способом. Покрытие как ошибок обработки в случае неправильного ввода, так и «преобразования» числа от 0 до 100 в буквы от A до F (или любого другого):

#!/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")

объяснение

  1. Сначала нам нужно получить номер от пользователя:

    n = int(input("number: "))
  2. Мы проверяем этот номер, чтобы он действовал для ряда условий:

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

    Для каждого из этих тестов результат будет либо либо, Falseлибо True. Поэтому (немного сжимая код):

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

    будет производить фигуру от 0до5

  3. Впоследствии мы можем использовать этот рисунок как индекс для строки, чтобы получить символ в качестве вывода, например

    "ABCDEF"[3] 

    выведет "D" (так как первый символ = "A")

  4. Дополнительным 101к списку является генерирование (Index-) ошибки в случае, если число превышает 100, так "ABCDEF"[6]как не существует. То же самое относится и к тому n = n if n>=0 else "", что создаст ошибку (Value-), если будет введено число ниже 0.
    В этих случаях, а также если ввод не является цифрой, результат будет:

    invalid input

Тесты:

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
Якоб Влейм
источник