Вопрос по bash – Клавиши со стрелками в корпусе bash

5

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

function main()  # The main function that controls the execution of all other functions
{
  mkdir -p ~/usertmp  # Make a new temporary user directory if it doesn't exist
  touch ~/last_seen_output.txt  # Create the output file if it doesn't exist
  cat /dev/null > ~/last_seen_output.txt  # Make sure that the output file is empty
  gather  # Call the "gather" function
  total=$((`wc -l ~/usertmp/user_list.txt|awk '{print $1}'`-1))  # Calculate the total amount of lines and subtract 1 from the result
  echo Current Time: `date +%s` > ~/last_seen_output.txt  # Print the current time to the output file for later reference
  echo "" > ~/last_seen_output.txt  # Print a blank line to the output file
    if [ $log -eq 1 ]
      then
        # If it is enabled, then delete the old backups to prevent errors
        while [ $line_number -le $total ]
          do

            line_number=$((line_number+1))  # Add 1 to the current line number
            calculate # Call the "calculate" function
            hms  # Call the "hms" function to convert the time in seconds to normal time
            log
        done
      else
        while [ $line_number -le $total ]
          do
            line_number=$((line_number+1))  # Add 1 to the current line number
            calculate # Call the "calculate" function
            hms  # Call the "hms" function to convert the time in seconds to normal time
            echo "Displaying, please hit enter to view the users one by one."
            read  # Wait for user input
            if [ "$log_while_displaying" ]
              then
                log
                display
              else
                display
            fi
        done
    fi
}

https://github.com/jbondhus/last-seen/blob/master/last-seen.sh это полный сценарий.

Команда чтения прокомментирована как «ожидание ввода пользователя» это команда, которую вы нажимаете ввод, чтобы перейти к следующему пользователю. По сути, в этом сценарии перечислены пользователи и время, прошедшее с момента входа каждого пользователя. Я пытаюсь переключаться между отображаемым пользователем с помощью клавиш со стрелками. Я подумал, что можно использовать оператор case для ввода ключа. Чтобы подтвердить мою точку зрения, я не уверен, возможно ли это. Если это не так, может кто-нибудь придумать другой способ сделать это?

Ваш Ответ

5   ответов
6

что это ответит на вопрос напрямую, но я думаю, что это связано - я бродил, откуда взялись эти коды, и наконец нашел:

Linux Keycode Table (comptechdoc.org)

Сначала трудно читать; для левой стрелки ищите «ВЛЕВО 4» в & quot; Ключе & quot; столбец, и для последовательности, котораяbash видит, ищите 5-й столбец («раскладка клавиатуры» - «нормальный»), где он записан как «[D 1b 5b 44»; - это три байта (27, 91, 68), представляющие этот ключ.

Нахождение темыКак читать стрелки на самом старом bash? - Форумы UNIX и Linux, вдохновил меня написать короткую однострочную строку, которая выводит коды клавиш нажатых клавиш. Как правило, вы нажимаете клавишу, а затем Enter (чтобы вызвать окончаниеread), а затем использоватьhexdump что вывестиread сохранен (и, наконец, нажмите Ctrl-C, чтобы выйти из цикла):

$ while true; do read -p?; echo -n $REPLY | hexdump -C; done
?^[[D     
00000000  1b 5b 44                                          |.[D| # left arrow
00000003
?^[[C
00000000  1b 5b 43                                          |.[C| # right arrow
00000003
?^[[1;2D
00000000  1b 5b 31 3b 32 44                                 |.[1;2D| # Shift+left arrow
00000006
?^[[1;2C
00000000  1b 5b 31 3b 32 43                                 |.[1;2C| # Shift+right arrow
00000006
?^C

Таким образом, в то время как клавиши со стрелками требуют 3 байта - Shift + клавиши со стрелками требуют 6! Однако, по-видимому, все эти последовательности начинаются с 0x1b (27), так что можно проверить это значение дляread -n1перед чтением больше байтов; также5b остается вторым байтом в многобайтовой последовательности для «нормального» значения; и & quot; сдвиг / NUM-Lock & quot; столбцы таблицы выше.

Редактировать: гораздо более простой и правильный способ поиска кодов терминала для нажатых клавиш в Linux - черезshowkey:

$ showkey 
Couldn't get a file descriptor referring to the console

$ showkey -h
showkey version 1.15

usage: showkey [options...]

valid options are:

    -h --help   display this help text
    -a --ascii  display the decimal/octal/hex values of the keys
    -s --scancodes  display only the raw scan-codes
    -k --keycodes   display only the interpreted keycodes (default)

$ sudo showkey -a

Press any keys - Ctrl-D will terminate this program

^[[A     27 0033 0x1b
         91 0133 0x5b
         65 0101 0x41
^[[B     27 0033 0x1b
         91 0133 0x5b
         66 0102 0x42
^[[A     27 0033 0x1b
         91 0133 0x5b
         65 0101 0x41
^[[D     27 0033 0x1b
         91 0133 0x5b
         68 0104 0x44
^[[C     27 0033 0x1b
         91 0133 0x5b
         67 0103 0x43
^C       3 0003 0x03
^M       13 0015 0x0d
^D       4 0004 0x04
12

клавиши курсора генерируют три байта - а клавиши типа home / end - даже четыре! Решение, которое я где-то видел, состояло в том, чтобы начальное чтение одного символа () следовало за тремя последующими чтениями одного символа с очень коротким тайм-аутом. Наиболее распространенные последовательности клавиш могут быть показаны следующим образом:

#!/bin/bash
for term in vt100 linux screen xterm
  { echo "$term:"
    infocmp -L1 $term|egrep 'key_(left|right|up|down|home|end)'
  }

Кроме того, / etc / inputrc содержит некоторые из них с отображениями readline. Итак, отвечая на исходный вопрос, вот фрагмент из этого меню, которое я просто взломал:

while read -sN1 key # 1 char (not delimiter), silent
do
  # catch multi-char special key sequences
  read -sN1 -t 0.0001 k1
  read -sN1 -t 0.0001 k2
  read -sN1 -t 0.0001 k3
  key+=${k1}${k2}${k3}

  case "$key" in
    i|j|$'\e[A'|$'\e0A'|$'\e[D'|$'\e0D')  # cursor up, left: previous item
      ((cur > 1)) && ((cur--));;

    k|l|$'\e[B'|$'\e0B'|$'\e[C'|$'\e0C')  # cursor down, right: next item
      ((cur < $#-1)) && ((cur++));;

    $'\e[1~'|$'\e0H'|$'\e[H')  # home: first item
      cur=0;;

    $'\e[4~'|$'\e0F'|$'\e[F')  # end: last item
      ((cur=$#-1));;

    ' ')  # space: mark/unmark item
      array_contains ${cur} "${sel[@]}" && \
      sel=($(array_remove $cur "${sel[@]}")) \
      || sel+=($cur);;

    q|'') # q, carriage return: quit
      echo "${sel[@]}" && return;;
  esac                  

  draw_menu $cur "${#sel[@]}" "${sel[@]}" "[email protected]" >/dev/tty
  cursor_up $#
done
Error: User Rate Limit Exceeded
6

а также другие клавиши без каких-либо необычных команд; вам просто нужно дваread звонки вместо одного:

escape_char=$(printf "\u1b")
read -rsn1 mode # get 1 character
if [[ $mode == $escape_char ]]; then
    read -rsn2 mode # read 2 more chars
fi
case $mode in
    'q') echo QUITTING ; exit ;;
    '[A') echo UP ;;
    '[B') echo DN ;;
    '[D') echo LEFT ;;
    '[C') echo RIGHT ;;
    *) >&2 echo 'ERR bad input'; return ;;
esac
8
# This will bind the arrow keys

while true
do
    read -r -sn1 t
    case $t in
        A) echo up ;;
        B) echo down ;;
        C) echo right ;;
        D) echo left ;;
    esac
done
Альтернативный ответ, который я оставил, используетread, но не запускается при других примененияхA, B, так далее.
Хороший трюк! Но это срабатывает и на Shift-a, например, и так ложно.
6

read -n 1 чтобы прочитать один символ, а затем использоватьcase заявление, чтобы выбрать действие, которое нужно предпринять на основе ключа.

Проблема заключается в том, что клавиши со стрелками выводят более одного символа, а последовательность (и ее длина) варьируется от терминала к терминалу.

Например, на терминале, который я использую, выводит стрелка вправо^[[C, Вы можете увидеть, какую последовательность выводит ваш терминал, нажавCtrl-V Right Arrow, То же самое верно для других клавиш управления курсором, таких какPage Up а такжеEnd.

Вместо этого я бы рекомендовал использовать односимвольные клавиши, такие как< а также>, Обработка их в вашем скрипте будет намного проще.

read -n 1 key

case "$key" in
    '<') go_left;;
    '>') go_right;;
esac
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededgithub.com/jbondhus/last-seen/blob/master/last-seen.shError: User Rate Limit Exceeded Jonathan Bondhus
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded((var += value))Error: User Rate Limit Exceeded((var++))Error: User Rate Limit Exceededvar=$((var+value))Error: User Rate Limit Exceeded((total_time -= mo * 2629746))Error: User Rate Limit Exceededvar=$((0))Error: User Rate Limit Exceededvar=0Error: User Rate Limit Exceededwhile (( line_number <= total ))Error: User Rate Limit Exceeded$()Error: User Rate Limit Exceededwc -l < filename
Error: User Rate Limit Exceeded Jonathan Bondhus

Похожие вопросы