Bash에서 특수 키 읽기

Bash에서 특수 키 읽기

저는 무엇보다도 선택 목록을 만드는 스크립트를 작업 중입니다. 좋다:

1)프로젝트 1              #(가장 밝은 부분)
2) 항목 2
삼)항목 3 #(선택됨)
4) 항목 4

  • 사용자가 다음 항목을 누를 때 down-arrow강조 표시
  • 사용자가 이전 항목을 누르면 up-arrow강조 표시됨
  • 등.
  • 사용자가 tab선택할 항목을 눌렀을 때
  • 사용자가 누르면 shift+tab모든 항목이 선택/선택 해제됩니다.
  • 사용자가 누르면 ctrl+a모든 항목이 선택됩니다
  • ...

현재 사용에서는 잘 작동합니다. 이는 입력이 내 설정에 따라 필터링되는 개인적인 사용 사례입니다.

문제는 이를 어떻게 다양한 단말에서 안정적으로 만들 것인가이다.


나는 입력을 읽기 위해 약간의 해키 솔루션을 사용합니다.

while read -rsn1 k # Read one key (first byte in key press)
do
    case "$k" in
    [[:graph:]])
        # Normal input handling
        ;;
    $'\x09') # TAB
        # Routine for selecting current item
        ;;
    $'\x7f') # Back-Space
        # Routine for back-space
        ;;
    $'\x01') # Ctrl+A
        # Routine for ctrl+a
        ;;
    ...
    $'\x1b') # ESC
        read -rsn1 k
        [ "$k" == "" ] && return    # Esc-Key
        [ "$k" == "[" ] && read -rsn1 k
        [ "$k" == "O" ] && read -rsn1 k
        case "$k" in
        A) # Up
            # Routine for handling arrow-up-key
            ;;
        B) # Down
            # Routine for handling arrow-down-key
            ;;
        ...
        esac
        read -rsn4 -t .1 # Try to flush out other sequences ...
    esac
done

등.


앞에서 언급했듯이 문제는 다양한 터미널에서 이를 어떻게 안정적으로 만들 것인가입니다. 즉, 특정 키를 정의하는 바이트 시퀀스가 ​​무엇인지입니다. 배쉬에서 이것이 가능합니까?

한 가지 아이디어는 주어진 결과를 기반으로 tputor 및 필터링을 사용하는 것입니다 . 하지만 실제로 키를 눌렀을 때 실제로 읽은 내용 과 infocmp둘 다 다르다는 점에서 난관에 부딪혔습니다 . 예를 들어 bash 대신 C를 사용하는 경우에도 마찬가지입니다.tputinfocmp

for t in $(find /lib/terminfo -type f -printf "%f\n"); { 
    printf "%s\n" "$t:"; 
    infocmp -L1 $t | grep -E 'key_(left|right|up|down|home|end)';
}

항복 순서는 예를 들어 에 의해 정의된 대로 읽혀지지만 에 의해 설정된 것은 linux아닙니다 .xtermTERM

예를 들어 왼쪽 화살표는 다음과 같습니다.

  • tput/ infocmp:\x1 O D
  • read:\x1 [ D

내가 무엇을 놓치고 있나요?

답변1

당신이 놓치고 있는 것은 대부분의 터미널 설명( linux하드코딩된 문자열의 일반적인 사용으로 인해 여기서는 소수만 .inputrc)이 다음을 사용한다는 것입니다.신청방법특수 키에 사용됩니다. 이렇게 하면 커서 키가 표시된 대로 표시 tput되고 infocmp(초기화되지 않은) 터미널이 전송하는 것과 달라집니다. 저주 응용 프로그램은 항상 터미널을 초기화하고 터미널 데이터베이스가 사용됩니다.저것목적.

dialog용도가 있지만 문제를 직접적으로 해결하지는 않습니다. 반면에 번거롭다(기술적으로실현 가능 한, 희귀한완벽한)는 bash 전용 솔루션을 제공합니다. 보통 우리는 이를 위해 다른 언어를 사용합니다.

특수 키를 읽을 때의 문제점은 일반적으로 escape및 와 같은 어색한 문자를 포함하여 여러 바이트라는 것입니다 ~. 당신은 할 수하다Bash를 사용하여 이를 수행하는 것이 가능하지만 이것이 어떤 특수 키인지 휴대용으로 결정하는 문제를 해결해야 합니다.

dialog둘 다 특수 키 입력을 처리하고 (일시적으로) 디스플레이를 대신합니다. 정말로 간단한 명령줄 프로그램을 원한다면 이것은 그렇지 않습니다 dialog.

다음은 특수 키를 읽고 이를 인쇄하는 간단한 C 프로그램입니다.인쇄 가능(그리고 이식 가능한) 형식:

#include <curses.h>

int
main(void)
{   
    int ch;
    const char *result;
    char buffer[80];

    filter();
    newterm(NULL, stderr, stdin);
    keypad(stdscr, TRUE);
    noecho();
    cbreak();
    ch = getch();
    if ((result = keyname(ch)) == 0) {
        /* ncurses does the whole thing, other implementations need this */
        if ((result = unctrl((chtype)ch)) == 0) {
            sprintf(buffer, "%#x", ch);
            result = buffer;
        }
    }
    endwin();
    printf("%s\n", result);
    return 0;
}

이것이 라고 가정하면 tgetch스크립트에서 다음과 같이 사용할 수 있습니다.

case $(tgetch 2>/dev/null) in
KEY_UP)
   echo "got cursor-up"
   ;;
KEY_BACKSPACE|"^H")
   echo "got backspace"
   ;;
esac

추가 자료:

답변2

을 사용해 보셨나요 dialog? 이는 대부분의 Linux 배포판에서 표준이며 체크리스트를 포함하여 다양한 텍스트 기반 대화 상자를 만들 수 있습니다.

예를 들어:

exec 3>&1 # open temporary file handle and redirect it to stdout

#                           type      title        width height n-items    
items=$(dialog --no-lines --checklist "Title here" 20    70     4 \
          1 "Item 1" on \
          2 "Item 2" off \
          3 "Item 3" on \
          4 "Item 4" off \
            2>&1 1>&3) # redirect stderr to stdout to catch output, 
                       # redirect stdout to temporary file
selected_OK=$? # store result value
exec 3>&- # close new file handle 

# handle output
if [ $selected_OK = 0 ]; then
    echo "OK was selected."
    for item in $items; do
        echo "Item $item was selected."
    done
else
    echo "Cancel was selected."
fi

당신은 다음과 같은 것을 얻을 것입니다 :

여기에 이미지 설명을 입력하세요.

출력은 다음과 같습니다:

 OK was selected.
 Item 1 was selected.
 Item 3 was selected.

(또는 원하는 프로젝트).

man dialog만들 수 있는 다른 유형의 대화 상자와 모양을 사용자 정의하는 방법에 대한 정보가 제공됩니다.

관련 정보