프로그램 출력이 터미널 프롬프트를 덮어쓰는 것을 방지합니다.

프로그램 출력이 터미널 프롬프트를 덮어쓰는 것을 방지합니다.

터미널에서 다음과 같은 명령을 실행한다고 가정해 보겠습니다.

~$ echo 'sleep 2; echo "hello!"' | sh

그런 다음 다음 줄을 입력하기 시작합니다. 2초 후에 내가 쓰고 있는 내용에 "hello!\n"이라는 단어가 삽입될 것입니다. 해결 방법이 있다는 것을 알고 있지만(프롬프트를 새로 고치려면 위로 누른 다음 아래로 누르십시오) 기록이 없는 다른 시스템에서는(예: 텔넷을 통해 MUD를 사용하는 경우) 불가능합니다.

stdin과 stdout을 분리하는 ncurses 애플리케이션이나 터미널 에뮬레이터를 아는 사람이 있나요? 이것은 ncurses에서 하기 매우 쉬운 것처럼 보입니다. 영리한 dup2를 사용하기만 하면 됩니다. 하지만 구현하기 전에 누군가가 이전에 해본 적이 있는지 알고 싶습니다.

주요 문제에 대한 다른 해결책도 환영합니다.

답변1

이것은 들리는 것처럼 변경하기가 쉽지 않습니다. 이는 터미널 "cooked" 대 "raw" 모드 및 "echo" 활성화 여부와 관련이 있습니다.

터미널이 베이크 모드(기본값)에 있을 때 커널은 입력으로 입력된 모든 항목을 읽고 일반 텍스트 즉시 에코, 삭제 처리, 문자 삭제(단일 문자 및 전체 문자 삭제)를 포함하는 기본 줄 편집 기능을 사용하여 이를 처리합니다. )은 각각 현재 줄의 내용과 다른 내용입니다. Enter 키를 누르면 실제로 터미널 입력에 텍스트 줄이 나타납니다. Enter 키를 누를 때까지의 전체 프로세스는 모두 커널 내부에서 발생합니다.터미널에서 실행 중인 프로세스가 단일 바이트를 수신하지 못했습니다., 따라서 포그라운드 애플리케이션은 사용자가 아무 것도 입력하고 있는지조차 알지 못합니다. tty에서 실행 중인 프로세스는 원하더라도 이 에코를 억제할 수 없습니다. 단순히 에코가 부적절한 시간(예: 출력과 혼합)에 나타날 것이기 때문입니다. 이러한 프로세스는 입력이 발생하고 있다는 사실조차 알지 못하기 때문입니다.

에코를 표시하지 않거나 stty rawtermios를 사용하는 대신 터미널을 원시 모드로 설정하여 이를 억제할 수 있지만 그러면 커널의 줄 편집 기능이 완전히 손실됩니다. 즉, 키를 누르고 다시 시작할 수 Ctrl없다는 의미입니다. u오류. 더욱이, 커널 요리 처리에 의존하는 프로그램(기본적으로 readline이나 ncurses를 사용하지 않는 모든 프로그램)을 사용하는 데 많은 어려움을 겪게 될 것입니다. 왜냐하면 그러한 프로그램에서는 완전히 맹목적으로 입력하게 되기 때문입니다! 아, 그리고 또한: 터미널을 처리하지 않으면 중단되고 보류 중인 작업 제어 바로 가기에 대한 커널 차단 기능이 손실됩니다(기본값은 각각 Ctrl- cCtrl- z).

답변2

echo출력을 화면 상단으로 보내기 위해 뒤에서 이스케이프되는 일부 ANSI를 포함할 수 있습니다 .

printf %b\\n 'sleep 2; printf "\0337\033[H\033[Khello!\0338"' |sh

가능해야합니다. 작동하려면 기본 ANSI 호환 터미널이 필요하지만 아직 그런 터미널이 없다면 아마도 그렇게 해야 할 것입니다. 다른 사람들은 1980년대부터 이 방법을 사용해 왔습니다.

각각의 경우에 선행은 \033리터럴의 8진수 이스케이프입니다.<ESC>문자 - 예를 들어 키보드의 왼쪽 상단 모서리를 누를 수 있습니다. 나머지 모든 시퀀스는 입력 시 터미널에서 커서 주소 지정 명령으로 해석됩니다.

그들은 다음과 같은 일을 합니다:

  • 7
    • 나중에 복원할 수 있도록 커서 상태를 저장합니다.
  • [H
    • 커서를 홈으로 이동 - 화면 첫 번째 행의 첫 번째 열로 이동합니다.
  • [K
    • 현재 줄의 텍스트를 지웁니다.
  • 8
    • 마지막으로 저장된 커서 상태를 복원합니다.

결과적으로 백그라운드 프로세스는 커서를 화면의 왼쪽 상단에 배치하고 줄을 지우고 다음을 씁니다.안녕하세요!를 클릭한 다음 커서를 찾은 위치로 다시 이동합니다. 더 복잡한 조합이 가능하며 더 강력한 솔루션을 개발하는 데 사용될 수 있지만 이것이 제가 얻은 것입니다.

답변3

내가 아는 유일한 해결책은 를 누르는 것입니다 ^R. 입력한 텍스트를 복원합니다. 완벽하지는 않지만 backspace한동안 고수했다가 다시 시작하는 것보다 낫습니다.

답변4

텔넷을 통해 게임을 플레이하는 경우의 사용 사례입니다. 저는 입력을 위해 별도의 터미널을 사용하곤 했습니다.

다음을 수행하여 입력 터미널을 생성합니다.

xterm -e bash -c "cat > '$(readlink -f /dev/stdin)'"

관련 정보