Lubuntu에서 Konsole의 문자 인코딩을 UTF-16으로 설정했습니다(Konsole이 UTF-16 리틀 엔디안을 사용하는지 UTF-16 빅 엔디안을 사용하는지 확실하지 않음).
그런 다음 실행 창에서 다음 명령을 실행했습니다.
그런 다음 키보드의 "a" 버튼(Lubuntu에서 선택한 키보드 레이아웃은 영어임)을 눌렀는데, 이로 인해 바이트 61 00
(Konsole이 UTF-16 리틀 엔디안을 사용하는 경우)가 다음으로 전송 될 것이라고 생각했습니다.라인 규율,게다가라인 규율이 바이트는 차례로 Konsole로 다시 에코되며 Konsole은 문자 "a"를 표시합니다. 그러나 나는 다음과 같은 결과를 얻습니다.
"a" 버튼을 다시 누르면 다음과 같은 결과가 나타납니다.
"a" 버튼을 다시 누르면 다음과 같은 결과가 나타납니다.
"a" 버튼을 다시 누르면 다음과 같은 결과가 나타납니다.
단순히 "aaaa"라는 문자가 표시되는 대신 이러한 이상한 문자가 표시되는 이유는 무엇입니까?
편집하다:
Konsole에 표시되는 문자는 다음과 같습니다.
각성`각성>각성`각성
답변1
xxd -p
이는 무관하다는 점을 더욱 강조하겠습니다 .아니요말하다그것은산출. 커널 측 라인 버퍼링으로 인해 입력도 볼 수 없으므로 출력도 생성되지 않습니다. 가치가 있는 것은 a cat
또는 a sleep 100000
또는 다른 것일 수도 있습니다 . 우리는 방법에 대해 이야기하고 있습니다핵심(라인 규칙) 에코 입력.
UTF-8로 다시 전환하고 Enter를 누르면 xxd -p
출력은 다음과 같습니다 fffe6100fffe6100
. 엔디안이 거의 확인되지 않았지만(또는 아키텍처의 기본 엔디안) 각 문자 앞에 BOM이 있다는 것은 놀라운 일입니다. Konsole 개발자가 이에 대해 제대로 생각하지 않은 것 같습니다. 그들은 사용 가능한 모든 입력 블록에 대해 대상 문자 세트로 UTF-16(BE 또는 LE가 지정되지 않음)을 사용하여 맹목적으로 iconv를 호출하고 iconv를 거기에 넣었습니다.
konsole을 사용하여 strace
연결된 파일 설명자에 어떤 작업을 수행하는지 살펴보겠습니다 /dev/ptmx
.
write(..., "\377\376a\0", 4) = 4
[...]
read(..., "\377\376a^@", 5) = 5
NUL 바이트(0x00)는 리터럴 ^@
, 0x5e 다음에 0x40으로 반환됩니다.
(0x61) 과 함께 a
U+5e61이 제공되며 이는 정확히 처음으로 표시되는 글리프입니다. 또한 한 바이트씩 차이가 발생합니다. 즉, 다음 하위 바이트가 상위 바이트로 해석되고 그 반대의 경우도 마찬가지입니다.
바이트의 경우 0x00
커널이 에코되는 방식을 깨뜨렸습니다. 다른 바이트의 경우 다른 작업도 수행합니다. 예를 들어, bytes 0x03
( ^C
)는 일반적으로 포그라운드 프로세스로 전송된 인터럽트를 트리거하고, 0x15
( ^U
)는 지금까지 입력한 데이터를 지우고 0x0a
/또는 0x0d
(예: 개행) 애플리케이션에 데이터를 플러시합니다. 이러한 모든 바이트는 UTF-16 문자 표현에 합법적으로 나타날 수 있으며 실제로 입력할 때 이런 일이 발생하는 것을 원하지 않습니다.
제자 라인에서 UTF-16을 사용하려면 커널은 이에 대한 명시적인 지원을 제공해야 하며 이 인코딩이 사용되고 있음을 알려야 합니다 stty utf16
( 내가 아는 한, 이것은 구현되지 않았습니다(다행히도 개발자 리소스가 완전히 낭비됩니다). 커널은 ASCII 호환 인코딩을 기대하지만 UTF-16은 그렇지 않습니다.
UTF-16이 tty 라인용 커널에서 구현되더라도 전체 생태계는 매우 취약할 수밖에 없습니다. 엔드포인트는 여러 소스에서 동시에 데이터를 수신할 수 있으며, 모든 데이터 생산자와 모든 전송자(예: SSH)가 항상 쌍별 바이트 결합을 유지한다는 보장은 없습니다. 위에 표시된 대로 바이트가 손실되면 나머지는 사용할 수 없습니다.
이제 Konsole 개발자가 이를 올바르게 고려하지 않았다는 것이 더 확실해졌습니다. 제 생각에는 UTF-16이 제공하는 인코딩 목록에서 제거되거나 최소한 경고가 표시되어야 한다고 생각합니다. 나는 제출했다Konsole 버그 395171.