[Linux 셸 스크립트] 사용자 인터페이스 - 005 사용자 키 입력을 한 글자만 받기(Enter 키 불필요)
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] 사용자 인터페이스 - 005 사용자 키 입력을 한 글자만 받기(Enter 키 불필요)

by 찬찬이 아빠 2021. 3. 2.
반응형
  1. 사용 명령어

(1) stty

(2) case

(3) dd

 

 

  2. 키워드 & 사용처

(1) 키워드

키보드, 입력, 줄바꿈, Enter

 

(2) 사용처

키보드에서 글자 하나가 입력되면 Enter 입력 없이 처리를 속행하고 싶을 때 사용합니다.

 

 

  3. 실행 예제
$ ./getchar.sh
Type Your Answer [y/n] : y
Input : Yes

 

 

  4. 스크립트

#!/bin/sh

 

echo-n "Type Your Answer [y/n] : "

 

# 현재 터미널 설정을 셸 변수 tty_state에 백업하고 터미널을 raw 설정함

tty_state=$(stty -g)             

stty raw                                 

 

# 키보드에서 문자 하나 읽기

char=$(dd bs=1 count=1 2> dev/null         

 

# 터미널 설정을 원래대로 돌림

stty "$stty_state"                 

 

 

echo

 

# 입력된 문자에 따라 처리 분기

case "$char" in                           

    [yY])

        echo"Input: Yes"

        ;;

    [nN])

        echo "Input : No"

        ;;

    *)

        echo "Input : What?"

         ;;

esac

 

 

  5. 해설

이 스크립트는 사용자에게 Yes/No를 물어서 입력된 문자로 Yes인지 No인지 판단해서 메시지를 표시합니다.

 

스크립트 실행 중에 계속 진행할지 여부를 확인하는 등 사용자에게 무언가를 입력받고 싶을 때 read 명령어를 써서 키 입력을 얻을 수 있는데 read 명령어는 반드시 줄바꿈이 필요합니다. 즉, 사용자는 문자를 입력한 다음 Enter 키를 눌러야만 합니다.

 

하지만 단순히 Yes/No를 묻는다면 Enter 키를 누르지 않고 y 또는 n을 누르면 처리를 진행하고 싶을 때 터미널(단말) 상태를 설정하는 stty 명령어로 터미널을 raw 모드로 하면 키 버퍼 처리를 하지 않으므로 문자마다 처리할 수 있습니다.

 

이 예제에서 줄 바꿈이 없는 메시지를 echo -n으로 표시한 다음, 처럼 현재 터미널 설정을 stty -g 명령어 출력 결과를 가지고 저장합니다. stty -g 출력은 다음과 같으며 현재 터미널 설정이 저장됩니다.

$ stty -g
2d00:5:bf:ca3b:3:1c:7f:15:4:0:1:0:11:13:1a:ff:12:f:17:16:ff:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

 

이후 raw 모드로 할 때 현재 터미널 설정이 지워지므로 나중에 설정을 원래대로 돌릴 수 있도록 현재 설정을 일시적으로 셸 변수 tty_state에 저장합니다.

 

처럼 stty raw 명령어로 터미널을 raw 모드로 전환합니다. 이러면 실제 키 입력갑슨 다음 dd 명령어에 직접 전달됩니다. 처럼 dd 명령어에서는 입출력 블록 크기를 1(bs=1), 입력에서 출력으로 복사하는 블록 수를 1(count=1)로 해서 입력된 문자를 셀 변수 char에 설정합니다.

 

또한, dd 명령어 실행 메시지는 필요 없으므로 /dev/null로 리다이렉트해서 버립니다. 이대로는 터미널이 raw 모드이므로 스크립트 실행 이전 상태로 되돌려야 합니다. 처럼 stty 명령어를 써서 stty "$tty_state"로 지정하면 사용자 터미널 상태는 raw 모드를 벗어나서 처음에 저장한 터미널 상태로 돌아갑니다. 입력된 값은 셸 변수 char에 들어있으므로 에서 처럼 case 분기합니다. 입력된 문자가 y 또는 Y라면 Yes 처리, n 또는 N이라면 No 처리를 합니다.

 

 

<Mac에서 echo 명령어>

Mac에서 echo 명령어는 조금 성가십니다. Mac에서 echo 명령어는 명령행에서 직접 사용할 때는 줄바꾸지 않는 -n 옵션이 동작합니다. 하지만 셸 스크립트 내부에서 echo -n은 옵션으로 지정한 "-n"이 문자열로 그대로 출력됩니다.

 

이것은 echo 명령어가 셸의 내부 명령어로 실행되는 것이 원인입니다. 셸 스크립트에서 이용하는 명령어로는 '외부 명령어'와 '셸 내부 명령어' 두 종류가 있습니다. 외부 명령어는 /bin/echo 처럼 실행 파일이 존재합니다. 한편, 셸 내부 명령어는 셸 자체 내부에 있는 명령어로 실행 파일이 존재하지 않습니다.

 

이 예제처럼 echo를 쓰면 내부의 echo 명령어가 사용됩니다. Mac에서는 기본 로그인 셀이 bash이므로 명령행에서는 bash의 셸 내부 echo 명령어가 실행됩니다. 이것은 -n에 대응하므로 원하는 대로 줄바꿈이 없게 실행됩니다.

 

한편, 스크립트 내부에 echo를 쓰면 bash가 아니라 sh 셸 내부인 echo 명령어가 실행됩니다. Mac의 sh 셸 내부 echo 명령어는 옵션 -n에 대응하지 않으므로 지정해도 인수로 해석되어서 "-n" 그대로 출력됩니다. 따라서 Mac에서 개행하지 않는 메시지를 echo로 출력하려면 다음처럼 외부 명령어 echo를 사용합니다.

/bin/echo -n "Type Toyr Answer [y/n] : "

또는 다음처럼 printf 명령어를 쓰는 방법도 있습니다. printf 명령어는 \n으로 지정하지 않으면 줄바꾸지 않으므로 그대로 출력됩니다.

printf "Type Your Answer [y/n] : "

 

 

 

참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전

반응형

댓글