POSIX 쉘과 awk가 입력 문자를 한 줄씩 읽지 않고 문자별로 읽도록 하려면 어떻게 해야 합니까?

POSIX 쉘과 awk가 입력 문자를 한 줄씩 읽지 않고 문자별로 읽도록 하려면 어떻게 해야 합니까?

POSIX 쉘과 awk가 입력 문자를 한 줄씩 읽지 않고 문자별로 읽도록 하려면 어떻게 해야 합니까?

로마자에서 가나로의 음역 응용 프로그램을 만들고 있는데 awk에 대한 입력을 문자별로 즉시 처리하고 싶습니다.

awk가 문자를 처리하기 전에 return이나 enter를 누르지 않고 이 작업을 수행하는 올바른 방법을 모르겠습니다.

답변1

쉘 스크립트에서 이 도구를 사용하여 TTY 상태를 조작할 수 있습니다 stty.

먼저 stty -g현재 상태를 나타내는 문자열을 생성합니다. 다른 작업을 수행하기 전에 이 출력을 캡처하여 어딘가에 저장하십시오. 나중에 이 문자열을 sttyTTY 설정을 복원 하는 유일한 인수로 전달할 수 있습니다 . 문자열에는 따옴표가 필요하지 않습니다. POSIX 표준에서는 stty -g쉘 스크립트에서 따옴표로 묶을 필요가 없는 표현을 생성해야 합니다.

stty raw한 번에 한 문자씩 입력할 수 있는 원시 모드로 들어가는 방법입니다.

savetty=$(stty -g)
stty raw
...
stty $savetty

스크립트가 어딘가에서 종료되거나 중단된 경우에도 설정을 복원하는 trap핸들러를 설정하려면 이 명령을 사용하는 것이 좋습니다.tty

stty이제 이 댄스를 Awk 코드로 래핑한다고 가정해 보겠습니다 . 일반성을 잃지 않고 Awk 외부에서 이 작업을 수행해 보겠습니다. awk가 한 번에 한 문자씩 읽도록 하려면 어떻게 해야 합니까?

awk는 암시적 스캔 전략이나 연산자를 사용하여 행을 읽을 수만 있습니다 getline. getchar아니요 아, 하지만 그 줄은 실제로는기록. GNU Awk에는 POSIX 표준의 일부가 아닌 두 가지 도구가 있습니다:

  1. 변수 RS에는 여러 문자가 포함될 수 있으며, 이 경우 정규식입니다.

  2. RT변수는 레코드 종결자와 일치하는 텍스트 조각을 보유합니다.

보다:

$ awk  'BEGIN { RS = "(.)" } { print NF, RT }'
How now brown cow.
0 H
0 o
0 w
0  
0 n
0 o
0 w
0  
0 b
0 r
0 o
0 w
0 n
0  
0 c
0 o
0 w
0 .
 

정규식 (.)(모든 문자와 일치)을 레코드 구분 기호로 사용하면 필드가 전혀 포함되지 않은 빈 레코드를 얻게 되며 빈 레코드를 종료하는 문자는 RTGNU Awk에서 사용할 수 있습니다.

불행히도 이것은 완전히 작동하지 않습니다. 이를 완전한 프로그램에 통합하면 다음과 같습니다.

#!/bin/sh

trap 'stty $ttysave' EXIT INT TERM
ttysave=$(stty -g)

stty raw -echo

awk  'BEGIN { RS = "(.)" }
      RT ~ /q/ { exit }
      { printf("[%s]", RT) }'

이는 이전 문자를 읽는 Gawk의 레코드 구분 정규식 기계에 문제가 있음을 보여줍니다. 예를 들어 를 입력하여 즉시 종료하려면 q이것 q만으로는 충분하지 않습니다. 현재 레코드를 구분할 수 있고 RT로 설정할 수 있더라도 Gawk는 레코드를 전달하기 전에 문자를 읽기 위해 TTY에서 다른 레코드를 q호출합니다 .read

for따라서 우리는 또는 while루프를 반복하고 dd유틸리티를 호출하는 것과 같은 정말 보기 흉한 방법에 의존해야 합니다 .

#!/bin/sh

trap 'stty $ttysave' EXIT INT TERM
ttysave=$(stty -g)

stty raw -echo

awk  'BEGIN { cmd = "dd bs=1 count=1 2> /dev/null"
              for (;;)
              { cmd | getline ch
                close(cmd)
                if (ch == "q")
                  exit
                printf("[%s]", ch) } }'

관련 정보