Bash가 두 개의 쉘 프롬프트를 작성하려고 시도합니까?


11

교육 목적으로 터미널에 연결된 실행중인 bash 프로세스의 strace 출력을보고 있습니다.

내 bash 프로세스에는 PID 2883이 있습니다.

나는 타이핑한다

[OP@localhost ~]$ strace -e trace=openat,read,write,fork,vfork,clone,execve -p 2883 2> bash.strace

터미널로. 그런 다음 bash 프로세스로 이동하여 다음과 같은 상호 작용이 있습니다.

[OP@localhost ~]$ ls

출력을 보면

strace: Process 2883 attached
read(0, "l", 1)                         = 1
write(2, "l", 1)                        = 1
read(0, "s", 1)                         = 1
write(2, "s", 1)                        = 1
read(0, "\r", 1)                        = 1
write(2, "\n", 1)                       = 1
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fec6b1d8e50) = 3917
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3917, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
write(1, "\33]0;OP@localhost:~\7", 23) = 23
write(2, "[OP@localhost ~]$ ", 22)  = 22
...

나는 마지막 두 줄에서 혼란스러워합니다. bash가 두 개의 쉘 프롬프트를 작성하려고하는 것 같습니다. 무슨 일이야?

답변:


24

<ESC>]0;시퀀스 (AS 도시 \33]0;strace를하여)는 단자 창 제목을 설정하는 제어 시퀀스이다. BEL 문자 ( \7)로 끝나 므로 첫 번째 write창 제목을 설정합니다. 두 번째는 실제 프롬프트를 인쇄합니다. 이스케이프 시퀀스를 제외하고는 정확히 동일하지는 않습니다. [..]창 제목에는없는 반면 프롬프트에는 주변 이 있습니다.

또한 첫 번째 쓰기는 stdout (fd 1, 첫 번째 인수는 write()), 두 번째 쓰기는 stderr 로 진행됨을 알 수 있습니다 . Bash는 stderr에 프롬프트를 인쇄하므로 첫 번째 쓰기는 다른 곳에서옵니다. 아마도 어딘가 아마도 PROMPT_COMMANDBash에 대한 데비안의 기본 시작 스크립트와 비슷할 것입니다 . 거기에 이와 같은 것이 있습니다 :

case "$TERM" in
xterm*|rxvt*)
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
    ;;
*)
    ;;
esac

PROMPT_COMMAND실행 중 xterm또는 이 경우 rxvt이스케이프 시퀀스를 지원하도록 설정합니다 .


bash가 한 번에 한 줄씩 읽는 대신 문자별로 물건을 읽는 것처럼 보이는 이유를 알고 있습니까? 또한 bash는 왜 "l"과 "s"를 stdout에 씁니까? 와 비슷한 strace를 수행하면 cat두 가지 차이점이 있습니다. 입력을 한 줄씩 읽고 입력을 다시 stdout으로 반향하는 동안 입력을 두 번 볼 수 있습니다 (입력하면 한 번, 고양이가 반향하면 한 번).
extremeaxe5

@ extremeaxe5는 기본적으로 Bash (또는 오히려 readline 라이브러리)가 터미널이 수행하는 다소 제한된 처리에 의존하는 대신 모든 명령 줄 처리 자체를 처리하기 때문입니다. 예를 들어 TAB 문자 또는 ^A(Ctrl-A) 또는 다양한 특수 문자를 누를 때 수행 할 작업을 결정하려면 입력을 즉시 가져와야합니다 . 또한 터미널의 에코를 끄므로 각 특정 입력 문자에 대해 무엇을 출력할지 결정할 수 있습니다 (TAB는 일반적으로 TAB을 출력하지 않습니다) cat. 그렇다면 dash명령 실행을 처리하지 않는을 실행하십시오 .
ilkkachu

실제로 Bash가 read()한 번에 하나의 바이트 만 읽도록 호출하는 이유 는 줄 바꿈을지나 읽을 수 없기 때문입니다. 줄 바꿈으로 인해 외부 프로그램이 실행되어 동일한 입력에서 읽을 수도 있습니다. 그것은 그것에 대해 걱정하지 않은 경우가 부를 수있는, (그리고 그 프로그램은. 줄 바꿈 후 모든 문자를 읽을 수 있어야합니다) read()더 큰 한도 및 원시 모드에서 터미널로, 아직 것입니다 일반적으로 입력을받을 한 번에 한 문자. (입력 문자가 얼마나 빨리 도착하고 프로세스가 예약
되었는지에 달려

Bash는 명령 줄 처리 자체를 수행하기 때문에 두 번째 주석은 사실 인 것처럼 보입니다.
extremeaxe5

@ extremeaxe5, 그렇습니다. 어쨌든 일반적인 경우이므로 그렇게 가정했습니다. 그러나 쉘이 터미널의 라인 편집에 의존하더라도 타이밍은 여전히 ​​문제가 될 수 있습니다. 두 줄이 빠르게 연속적으로 전송되고 (데이터 붙여 넣기를 생각할 때) 시스템이 충분히로드되어 셸이 즉시 예약되지 않았거나 (또는 ​​셸이 중지 된 경우) read()더 큰 버퍼가있는 경우 여전히 두 줄을 모두 반환 할 수 있습니다. 같은 전화. 내가 보장이 생각하지 않는 read()것입니다 항상 요리 모드에서 하나의 행을 반환.
ilkkachu '11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.