在bash中套管箭头键

Jon*_*hus 6 bash

如果按下向上/向左箭头键,是否可以在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
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/jbondhus/last-seen/blob/master/last-seen.sh是完整的脚本.

读取命令注释为"等待用户输入"是您输入以转到下一个用户的命令.基本上,这个脚本的用途是列出用户以及自每个用户登录以来所经过的时间.我正在尝试使用箭头键在显示的每个用户之间切换.我认为可以使用case语句来表示键输入.重申我的观点,我不确定这是否可行.如果不是,有人能想到另一种方法吗?

eMP*_*584 15

如前所述,光标键生成三个字节 - 像home/end这样的键甚至生成四个字节!我在某处看到的解决方案是让初始的one-char read()跟随三个后续的one-char读取,并且超时很短.最常见的键序列可以像这样显示:

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

此外,/ etc/inputrc包含一些带有readline映射的..所以,回答原始问题,这里是来自该bash菜单的剪辑我只是在骇客:

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[@]}" "$@" >/dev/tty
  cursor_up $#
done
Run Code Online (Sandbox Code Playgroud)


小智 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
Run Code Online (Sandbox Code Playgroud)


Pau*_*ce. 7

您可以使用read -n 1读取一个字符,然后使用case语句根据键选择要执行的操作.

问题是箭头键输出多个字符,序列(及其长度)因终端而异.

例如,在我正在使用的终端上,右箭头输出^[[C.按Ctrl- 可以查看终端输出的顺序V Right Arrow.对于其他光标控制键,例如Page Up和,也是如此End.

相反,我建议使用像<和的单字符键>.在脚本中处理它们会简单得多.

read -n 1 key

case "$key" in
    '<') go_left;;
    '>') go_right;;
esac
Run Code Online (Sandbox Code Playgroud)


sda*_*aau 6

不确定这是否直接回答了问题,但我认为这是相关的 - 我在这些代码来自哪里徘徊,我终于找到了:

起初读起来有点困难; 对于左箭头,在"Key"列中查找"LEFT 4",对于查看的序列bash,查找第5个("keymap" - "normal")列,其中写为"[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
Run Code Online (Sandbox Code Playgroud)

因此,虽然箭头键需要3个字节 - Shift +箭头键需要6个!但是,看起来所有这些序列都以0x1b(27)开头,因此可以read -n1在读取更多字节之前检查此值; 还5b保留在多字节序列的"正常"和"移/ NUM锁"上面的表中的列的第二个字节.


编辑:更简单,更正确的方法来扫描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
Run Code Online (Sandbox Code Playgroud)


Jel*_*Cat 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
Run Code Online (Sandbox Code Playgroud)


djo*_*orn 5

使用eMPee584答案,我想我为您提出了一个很好的解决方案。它的输出与user3229933answer非常相似,但不会被 shift 键触发,并且可以在大多数终端中使用。

它有 UP DOWN LEFT RIGHT HOME 和 END 键按“q”退出大部分这要归功于 eMPee584

如果您收到类似illegal option n.

#!/bin/bash

while read -sn1 key # 1 char (not delimiter), silent
do

  read -sn1 -t 0.0001 k1 # This grabs all three symbols 
  read -sn1 -t 0.0001 k2 # and puts them together
  read -sn1 -t 0.0001 k3 # so you can case their entire input.

   key+=${k1}${k2}${k3} 

  case "$key" in
    $'\e[A'|$'\e0A')  # up arrow
        ((cur > 1)) && ((cur--))
        echo up;;

    $'\e[D'|$'\e0D') # left arrow
        ((cur > 1)) && ((cur--))
        echo left;;

    $'\e[B'|$'\e0B')  # down arrow
        ((cur < $#-1)) && ((cur++))
        echo down;;

    $'\e[C'|$'\e0C')  # right arrow
        ((cur < $#-1)) && ((cur++))
        echo right;;

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

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

    q) # q: quit
        echo Bye!
        exit;;

   esac                  

done
Run Code Online (Sandbox Code Playgroud)