Что я должен рассмотреть, чтобы написать сценарий, который реагирует на нажатие клавиши?

Я знаю, что могу читать внутри скрипта что-то в переменной, например: variable = read Но мне нужно нажать enter, чтобы отправить значение в переменную. Что мне нужно знать, чтобы представить значение нажатия клавиши в переменную без попадания в нее, или, если не передать в переменную, просто чтобы реагировать при нажатии определенного ключа?

2 Solutions collect form web for “Что я должен рассмотреть, чтобы написать сценарий, который реагирует на нажатие клавиши?”

С помощью bash вы можете использовать параметр -n для встроенной функции read чтобы ограничить количество прочитанных символов, не требуя новой строки:

 #!/bin/bash echo "Ready? [Y/n]: " read -n 1 y_or_n echo case "$y_or_n" in [Yy]|"") echo "you said yes" ;; *) echo "you said no" ;; esac 

Это работает, если bash вызывается как sh или bash .

Для получения дополнительной информации см. Справочное руководство или help read страницу bash .

Обратите внимание, что другие оболочки могут не поддерживать параметр -n для read . dash , например, нет.

Дело в том, что read оболочки – это ограничение вашего общего количества байтов на read или нет – это все равно не даст вам нажатия клавиши для каждого read . Это будет только фиксированное количество символов для каждого read . Чтобы получить нажатие клавиши для read вам нужно заблокировать свой вход – и лучший способ сделать это, вероятно, будет dd . Это функция оболочки, которую я написал пару месяцев назад, когда я экспериментировал с блокировкой w / dd на терминале i / o:

 printkeys()( IFS= n=1 set -f -- "$(tty <&2)" exec <${1##[!/]*};set \\t _dd()( c=conv=sync,unblock i=ibs=72 b=bs=8 dd bs=7 ${c%,*} | dd $io$bc$b $c ) 2>/dev/null trap " trap '' TTOU TTIN stty '$(stty -g stty raw isig inlcr)' " INT EXIT _dd |while ${2:+:} read -rc || exit 2 do case $#:$c in (1:): ;; (*:?*) set ":%d$@" \ \'${c%"${c#?}"} ; c=${c#?} ;; (*) printf "$@" ; [ 0 -eq $((n=n<4?n+1:0)) ] && set '\n\r'||set \\t ;; esac done ) 

Вы видите, что в вышеупомянутом случае вход терминала фильтруется по двум процессам dd в конвейере. Терминал устанавливается в режиме « stty to raw » в trap которая также восстанавливает состояние терминала на INT errupt или EXIT до того, что было при вызове функции (что может быть сделано с помощью CTRL + C, вероятно, или независимо от вашего ключа прерывания) , В необработанном режиме терминал сбрасывает ввод на любой считыватель, как только он приходит – нажатие клавиши. Он не просто нажимает байт за раз; он выталкивает весь буфер, как только это возможно. Итак, когда вы нажимаете стрелку ВВЕРХ, например, и ваша клавиатура отправляет escape-последовательность, например:

 ^[[A 

… который три байта, и он толкает все сразу.

dd должен удовлетворять любому чтению, как только он предлагается – независимо от того, насколько высок вы установите его ibs= . Это означает, что, хотя я установил его с помощью ibs=7 , когда терминал нажимает только три байта, чтение все еще завершено. Теперь это трудно справиться с большинством других полезных \0NUL , но dd 's conv=sync заполняет разницу w / \0NUL байт. Поэтому, когда вы нажимаете стрелку ВВЕРХ на клавиатуре, dd считывает три байта и записывает 7 в следующий dd – три байта в escape-последовательности и еще 4 \0NUL .

Но чтобы вытащить эти данные с помощью прочитанного shell, вы должны его снова заблокировать, поэтому следующий dd синхронизирует свой входной буфер с 72 байтами, но он также conv=unblock s it. При преобразовании unblock dd разбивает свой вход на \n разделители ewline для своего cbs= count – который находится здесь 8. С sync и unblock (или block ) конверсий dd не синхронизируется с \0NUL s, а скорее в конечных \0NUL , Таким образом, для каждых 7 байтов первый dd записывает в канал между ними, второй dd буферирует 72 байта – первые несколько – это то, что было \0NUL , затем \0NUL s, а затем 65 пробелов в хвосте каждого считывания.

Другое unblock – это конечные пробелы – он будет есть столько мест, сколько могло бы произойти в конце каждого из его блоков cbs= conversion. Так что, поскольку dd записывает вывод в obs=8 байт на запись, он записывает 9 строк на чтение в 2 полной записи в выходной канал. Первая запись – первая строка и состоит из 7 байтов, считанных из входного канала, и завершающей новой строки – еще одного байта. Следующая запись – 8 новых строк – все сразу и подряд – еще 8 байт – потому что dd ест все 8 пробелов для каждого из этих 8 блоков преобразования.

С другой стороны этих двух оболочек dd sa while цикл read s строчно. Он может игнорировать пустые строки – поскольку терминал преобразует все символы новой строки в возврат каретки на выходе в любом случае в соответствии с inlcr stty . Но когда он обнаруживает даже один байт в $c после того, как ввод оболочки read в его значение, тогда у вас есть нажатие клавиши – и целое, если ваша клавиатура не отправляет более 7 байт за нажатие клавиши (хотя это просто нужен другой блокирующий фактор) .

Когда оболочка имеет ключевое слово в $c она выполняет итерацию по байту для байта и разбивает его на массив, деленный на ' символы», а затем printf десятичные значения для каждого байта в $c все сразу. Если вы запустите эту функцию, вы должны получить вывод следующим образом:

 a:97 b:98 c:99 d:100 e:101 f:102 ;:59 ^M:13 ^M:13 ^M:13 s:115 a:97 d:100 f:102 :32 ':39 ':39 ':39 a:97 s:115 d:100 f:102 ;:59 ':39 ^[[A:27:91:65 ^[[D:27:91:68 ^[[B:27:91:66 ^[[C:27:91:67 ^[[D:27:91:68 ^[[C:27:91:67 ^[[A:27:91:65 ^[[D:27:91:68 ^[[C:27:91:67 ^[[B:27:91:66 ^[[D:27:91:68 ^[[C:27:91:67 ^[[A:27:91:65 ^[[D:27:91:68 ^[[C:27:91:67 ^[[B:27:91:66 

Поскольку \0NUL s, который вставляет dd для блокировки нажатия клавиш, как только оболочка заполняет значение переменной своим вводом – вы не можете поместить \0NUL s в переменную оболочки (в любой оболочке, но zsh – в этом случае он по-прежнему настраивается таким образом) . Насколько я знаю, это должно работать в любой оболочке – и это определенно работает в bash , dash и ksh93 . Он может даже надежно обрабатывать многобайтовые входные данные, но я не буду к этому ругаться.

В демонстрационном выводе выше фактический вывод функции предшествует каждой записи другой информацией, которую он не пишет. Каждый отображаемый символ, предшествующий каждому первому событию : в любой из вышеперечисленных последовательностей фактически является echo терминала, который может быть настроен с помощью -echo или stty echo -echo . Остальное – это то, что напечатано как выход функции – и оно печатается, как вы можете видеть, сразу же после его ввода.

  • Удалить разрыв строки в файле tex
  • Сценарий Bash для сканирования файлов для слов и создания отчета
  • удалить строки в файле list_file из другого файла (ов)
  • Apt-get не работает в bash-скрипте?
  • Убейте запущенный сценарий оболочки и убейте весь процесс, запущенный внутри него
  • Папки, созданные со сценарием, имеют неправильную измененную метку времени
  • Подключение 3 соединений OpenVPN через скрипт оболочки
  • Как хранить цветной текст в переменной и печатать его с цветом позже?
  • Терминал не вызывает «then», сообщает синтаксическую ошибку, а команда не найдена
  • Как обрабатывать ряд парных файлов
  • Расширение параметра Shell
  • Linux и Unix - лучшая ОС в мире.