Тайм-аут чтения bash только для первого введенного пользователем символа - PullRequest
3 голосов
/ 18 апреля 2019

Я искал простое решение, которое будет читать пользовательский ввод со следующими функциями:

  • тайм-аут через 10 секунд, если пользователь вообще не вводит
  • пользователь имеет бесконечное время, чтобы закончить свой ответ, если первый символ был набран в течение первых 10 секунд.

Я нашел решение для аналогичного запроса (время ожидания после каждого набранного символа) на Linux Read - время ожидания после x секунд * бездействия *. Тем не менее, это не совсем та функция, которую я искал, поэтому я разработал двухстрочное решение следующим образом:

read -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read b && echo "Your name is $a$b" || echo "(timeout)"

В случае, если пользователь ждет 10 секунд, прежде чем он введет первый символ, вывод будет:

What is your name? > (timeout)

Если пользователь вводит первый символ в течение 10 секунд, у него есть неограниченное время для выполнения этой задачи. Вывод будет выглядеть следующим образом:

What is your name? > Oliver
Your name is Oliver

Тем не менее, есть следующее предостережение : первый символ не может быть отредактирован, после того как он был напечатан, тогда как все остальные символы могут быть отредактированы (возврат и повторный ввод).

Есть ли у вас какие-либо идеи для разрешения предостережения или у вас есть другое простое решение для запрашиваемого поведения?

Ответы [ 4 ]

1 голос
/ 18 апреля 2019

Это решение может подойти.

read -n1 -t 10 -p "Enter Name : " name && echo -en "\r" &&
read -e -i "$name" -p "Enter Name : " name || echo "(timeout)"

Примечание: Второй read использует текст, захваченный из первого (опция -i), для предоставления редактируемого буфера. Возврат каретки и та же подсказка создают у пользователя впечатление, что он вводит то же значение.

1 голос
/ 18 апреля 2019

Включить readline и добавить $a в качестве значения по умолчанию для второго чтения.

# read one letter, but don't show it
read -s -N 1 -t 10 -p "What is your name? > " a

if [ -n "$a" ]; then
  # Now supply the first letter and let the user type
  # the rest at their leisure.
  read -ei "$a" b && echo "Your name is $b"
else
  echo "(timeout)"
fi

По-прежнему отображается второе приглашение после ответа на первое письмо, но я не думаю, что естьлучший способ справиться с этим;нет способа "отменить" тайм-аут для read.Идеальным решением было бы использовать какую-то команду , отличную от , отличную от read, но вы должны написать ее самостоятельно (вероятно, как загружаемую встроенную в C).

0 голосов
/ 18 апреля 2019

Краткий ответ:

Добавить параметр -s для первой команды чтения и параметр -ei для второй команды чтения:

read -s -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"

Или с лучшей обработкой пустого ввода:

read -s -N 1 -t 10 -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""

Уточненный ответ:

С помощью ответа @ chepner (спасибо за опцию -ei!) И комментария @ paul-hodges, которая привела меня к статье, пропагандирующей опцию -s read, я смог создать рабочий раствор очень похож на мой оригинальный 2-х линейный:

read -N 1 -t 10 -s -p "What is your name? > " a
[ "$a" != "" ] && read -ei "$a" b && echo "Your name is $b" || echo "(timeout)"

Некоторым из вас может понравиться более сложная версия той же функциональности:

if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
  read -ei "$FIRST_CHARACTER" FULL_NAME
  echo "Your name is $FULL_NAME"
else
  echo "(timeout)"
fi

Пояснение:

  • Опция -s в первой команде чтения гарантирует, что FIRST_CHARACTER не будет распечатан во время ввода.
  • опция -N 1 или -n1 обеспечит чтение только первого символа в переменной FIRST_CHARACTER
  • опция -ei будет читать $FIRST_CHARACTER в FULL_NAME, прежде чем пользователь продолжит писать символы от 2 до n.
  • пользователь может пересмотреть свой ответ, и он может удалить весь ввод, включая первый символ с пробелом.

У меня есть тест, и комбинация этих опций, кажется, помогает.

Устранение предостережения с пустым вводом

Однако есть небольшое предупреждение: если пользователь просто набирает <enter>: вторая команда чтения будет ждать ввода, пока пользователь не нажмет <enter> второй раз. Это можно исправить следующим образом:

if read -N 1 -t 10 -s -p "What is your name? " FIRST_CHARACTER; then
  if [ -n "$FIRST_CHARACTER" ]; then
    read -ei "$FIRST_CHARACTER" FULL_NAME
  else
    echo
  fi
  echo "Your name is \"$FULL_NAME\""
else
  echo "(timeout)"
fi

В стиле с двумя линиями это даст нам три линии следующим образом:

read -N 1 -t 10 -s -p "What is your name? > " a || echo "(timeout)" \
  && [ -n "$a" ] && read -ei "$a" b || echo \
  && echo "Your name is \"$b\""
* * Тест тысяча сорок-девять

Код обеих версий (вложенная версия if и трехстрочный) будет вести себя следующим образом:

  • Если пользователь ничего не делает в течение 10 секунд, вывод выдаст
What is your name? (timeout)
  • Если пользователь пишет Oliver<enter>, вывод будет
What is your name? Oliver
Your name is "Oliver"
  • если пользователь начинает писать «Оливер», а затем считает, что хочет, чтобы его звали «Майкл», он может полностью удалить «Оливер» с помощью клавиши возврата и заменить его соответствующим образом. Выход будет:
What is your name? Oliver

после ввода имени "Оливер". Затем, после нажатия клавиши Backspace 6 или более раз:

What is your name?

и после ввода Michael<enter>:

What is your name? Michael
Your name is "Michael"

Надеюсь, это поможет.

0 голосов
/ 18 апреля 2019

Условия тестирования: GNU bash, версия 4.4.19 (1) -релиз Ubuntu 18.04.2 LTS

Я создал функцию, чтобы решить вашу проблему с первой буквой, которую нельзя редактировать, как показано ниже.Я проверил это только на своем локальном сервере Linux, и я не предполагаю, что это будет работать в другом месте или с более новыми / более старыми версиями BASH (или читал в этом отношении, но я не смог сказать, какая версия была запущена)

__readInput(){
    str="What is your name? > "
    tput sc                       # Save current cursor position
    printf "$str"
    read -n 1 -t 10 a             # Wait 10 seconds for first letter
    [[ $? -eq 0 ]] || return 1    # Return ErrorCode "1" if timed_out
    while :; do                   # Infinite Loop
        tput rc                   # Return cursor to saved position
        printf "$str$a"           # Print string (including what is saved of the user input)
        read -n 1 b               # Wait for next character
        if [[ $? -eq 0 ]]; then
            # We had proper user input
            if [[ ${#b} -eq 0 ]]; then
                # User hit [ENTER]
                n=$a$b
                break             # End our loop
            fi
            rg="[A-Za-z-]"        # REGEX for checking user input... CAVEAT, see below
            if ! [[ $b =~ $rg ]] ;then
                # We have an unrecognisied character return, assume backspace
                [[ ${#a} -gt 0 ]]&&a=${a:0:(-1)}   # Strip last character from string
                tput rc           # Return cursor to saved position
                printf "$str$a   " # This removes the ^? that READ echoes on backspace
                continue          # Continue our loop
            fi
            a=$a$b                # Append character to user input
        fi
    done
}

Вы можете вызвать эту функцию, как показано ниже:

declare n=""
__readInput
if [[ $? -eq 0 ]] || [[ ${#n} -eq 0 ]] ;then
    echo "Your name is $n"
else
    echo "I'm sorry, I didn't quite catch your name!"
fi

ПРЕДУПРЕЖДЕНИЕ О ПРОЯВЛЕНИИ ВЫШЕ ОБЪЯСНЕНО Итак, у вас есть предупреждение, которое я исправил, возможно, вы (илинаши друзья) может исправить это.Любой введенный символ, который не включен в переменную $rg REGEX, будет рассматриваться как BACKSPACE.Это означает, что ваш пользователь может нажать F7, =, \ или буквально любой символ, отличный от указанных в $rg, и он будет рассматриваться как возврат

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...