bash scripting - чтение одного нажатия клавиши, включая специальные клавиши ввода и пробела

Не уверен, следует ли мне поместить это в stackoverflow или unix.stackexchange, но я нашел некоторые похожие вопросы здесь, так что вот.

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

Вот что я получил до сих пор:

#!/bin/bash

SELECT=""
while [[ "$SELECT" != $'\x0a' && "$SELECT" != $'\x20' ]]; do
    echo "Select session type:"
    echo "Press <Enter> to do foo"
    echo "Press <Space> to do bar"
    read -s -N 1 SELECT
    echo "Debug/$SELECT/${#SELECT}"
    [[ "$SELECT" == $'\x0a' ]] && echo "enter" # do foo
    [[ "$SELECT" == $'\x20' ]] && echo "space" # do bar
done

Следующий вывод — это то, что я получаю, если нажимаю Enter, пробел, Backspace и x:

:~$ bin/sessionSelect.sh
Select session type:
Press <Enter> to start/resume a screen session
Press <Space> for a regular ssh session
Debug//0
Select session type:
Press <Enter> to start/resume a screen session
Press <Space> for a regular ssh session
Debug//0
Select session type:
Press <Enter> to start/resume a screen session
Press <Space> for a regular ssh session
Debug//1
Select session type:
Press <Enter> to start/resume a screen session
Press <Space> for a regular ssh session
Debug/x/1

Таким образом, ввод и пробел приводят к пустому SELECT. Никак не отличить их друг от друга. Я пытался добавить -d 'D' к параметрам чтения, но это не помогло. Может быть, кто-то может указать мне в правильном направлении.

Версия bash будет 4.2 кстати.


person a.peganz    schedule 03.04.2014    source источник
comment
связанный unix .stackexchange.com/questions/179191/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 15.11.2017


Ответы (3)


Попробуйте установить разделитель чтения на пустую строку, а затем проверьте встроенную переменную $REPLY:

read -d'' -s -n1

По какой-то причине я не мог заставить его работать, указав переменную.

person Cole Tierney    schedule 03.04.2014
comment
Это прекрасно работает даже без изменения разделителя с помощью -d. И ввод, и пробел распознаются правильно. - person a.peganz; 03.04.2014
comment
У нас, наверное, разные вкусы read. Если я пропущу -d'', я не получу клавишу ввода. - person Cole Tierney; 04.04.2014
comment
Я только что заметил, что мы используем -n и -N соответственно. Это должно быть причиной того, что при указании длины с -N новые строки не обрабатываются специально. - person a.peganz; 04.04.2014
comment
Я собирался проверить с опцией -N, но в моем чтении ее нет. - person Cole Tierney; 04.04.2014

Здесь есть несколько важных моментов, касающихся read:

  • Он читает одну строку
  • Строка разбивается на поля, как при разбиении на слова.

Поскольку вы читаете один символ, это означает, что ввод Enter приведет к пустой переменной.

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

Измените свой оператор read на:

IFS= read -s -n 1 SELECT

и ожидать нулевую строку вместо $'\x0a' при вводе Enter.

person devnull    schedule 03.04.2014
comment
Это также работает, и с установкой IFS только для команды чтения в основном такое же чистое решение. Я по-прежнему отметил патнамхиллов как правильный, потому что он не может вызвать случайных побочных эффектов из-за измененного IFS. Хотя проголосовал! Кстати, с -N вместо -n SELECT не пуст при отправке ввода, а фактически содержит ожидаемое значение. - person a.peganz; 03.04.2014

person    schedule
comment
IFS='' не требуется. read -N вернет ввод как есть, игнорируя IFS (см. справочную страницу). Протестировал это без IFS='', работает нормально. Отличный ответ! Использовал это для реализации моей собственной версии '--More--'. - person Maxxim; 10.05.2019
comment
@Maxxim Это может быть в более новой версии Bash. По крайней мере, для Centos 7.6 с bash-4.2.46(2) требуется IFS=''. - person Andrey; 13.05.2019
comment
Ты прав. Это изменение было введено в Bash 4.4. На странице man на read -N nchars было добавлено следующее: [...] Результат не разбивается на символы в IFS; цель состоит в том, чтобы переменной присваивались точно считанные символы (за исключением обратной косой черты; см. параметр -r ниже). Хотите отредактировать свой ответ и указать на это, поможет ли это другим? - person Maxxim; 14.05.2019
comment
@Maxxim, основываясь на этом (неофициальном) списке изменений, трудно сказать как именно ведет себя данный экземпляр bash (было много ошибок с обработкой IFS). Также не забывайте об бэкпорте. - person Andrey; 20.05.2019