zsh 모듈 zsh/zpty는 Apple M1 macOS 시스템에서 실행되는 Linux 가상 시스템에서 제대로 실행되는 것 같습니다. 그러나 macOS에서는 동일한 방법이 작동하지 않습니다(동일한 호스트에서도). 저는 macOS에 사전 설치된 zsh 버전 /bin/zsh
과 homebrew에서 설치된 zsh 버전 모두에서 이것을 시도했습니다.
내 관찰에 따르면 zpty 명령을 실행하여 의사 터미널을 만들고 그 안에서 명령을 실행하면 실제로 프로세스가 생성됩니다. 그러나 글쓰기 과정이 작동하지 않습니다. 다음은 몇 가지 예입니다. 대화형 zsh 세션에서 다음 명령을 하나씩 입력했습니다.
zmodload zsh/zpty
zpty -b hello 'vim --clean'
zpty -w hello ':e foo'
zpty -w hello $'aHello there from foo file\e:w'
cat foo
zpty -d hello
macOS에서는 cat
실패하고 cat: foo: No such file or directory
Linux에서는 이 표시됩니다 Hello there from foo file
.
zpty로 무엇을 달성하고 싶나요? 의사 터미널에서 프로세스를 시작하고 zsh 수동 약속에 따라 비동기식으로 입력을 보내고 싶습니다. 나는 프로세스의 표준 출력에 관심이 없습니다. 이상적인 솔루션은 CPU 리소스를 묶거나 지연 루프 없이 모든 표준 출력을 폐기하는 것입니다. 또한 expect
다른 외부 프로그램을 사용하는 대체 솔루션을 찾고 있지 않습니다 .
이것은 zsh 또는 macOS 버그입니까? dtrace처럼 우회가 가능한가요?이것? 그런데 그것이 SIP(System Integrity Protection)와 관련이 있다면 놀랄 것입니다.
답변1
나는 이것이 귀하의 코드에 있는 버그라고 말하고 싶습니다. 이는 작동할 수도 있고 작동하지 않을 수도 있음을 의미합니다. Linux에서 작동한다는 사실이 다른 사람에게도 작동할 것이라는 보장도 없고 Linux가 macOS보다 낫다는 의미도 아닙니다.
- vim에 명령을 보내고 vim이 반응할 때까지 기다리지 않습니다. 따라서
foo
결국에는 이런 일이 발생할 가능성이 높지만 zsh가 더 빠르며 파일이 준비되기 전에 확인합니다. 이는 vim과 zsh의 상대적 실행 속도에 따라 달라지며, 이는 각각의 정확한 버전, 시스템 라이브러리, 운영 체제 커널, CPU, 문 페이즈 등에 따라 달라질 수 있습니다. - 터미널에서는 데이터를 읽을 수 없으므로 쓰는 동안 vim이 차단될 수 있습니다. 멈추는지 여부는 vim이 얼마나 쓰고 싶어하는지(시스템 라이브러리(특히 Curses)와 terminfo 항목에 따라 달라질 수 있음)와 터미널이 데이터를 소비하기 전에 터미널 인터페이스에서 쓸 수 있는 양에 따라 다릅니다(이는 vim의 커널, 어쩌면 zsh에서 사용하는 시스템 라이브러리에 있을 수도 있음).
올바른 해결책은 vim이 원하는 작업을 수행했음을 확인할 때까지 터미널에서 데이터를 읽는 것입니다. 즉, "B write" 줄을 기다리는 것입니다. 이렇게 하면 vim이 차단되지 않고 충분히 오래 기다릴 수 있습니다.
macOS에서 몇 가지 실험을 했지만 디버거에서는 볼 수 없었습니다. 이 코드를 사용해 보세요. 잠시 기다린 후 vim이 작성한 모든 내용을 읽고 특정 확인을 기다리지 않고 파일을 확인합니다.
rm -f foo
zpty -b hello 'vim --clean'
zpty -w hello ':e foo'
zpty -w hello $'iHello there from foo file\e:w'
sleep 0.02
zpty -r hello > >(xxd)
ls foo
zpty -d hello
나에게는 foo
이것을 실행할 때 그것이 있을 수도 있고 없을 수도 있습니다. sleep
시스템 값을 임계값에 더 가깝게 조정 해야 할 수도 있습니다 . 내 컴퓨터에서는 sleep 0.2
must가 foo
항상 존재하고 생략이 sleep
항상 존재하지 foo
않습니다. 그러나 위에서 쓴 것처럼 이는 다양한 매개변수에 따라 달라질 수 있습니다.
다음 코드는 foo
저장될 때까지 안정적으로 기다립니다(Vim의 메시지에 가 포함되어 있다고 가정하고 대신 내 구성으로 실행 B written
하면 메시지에 가 포함됩니다 ).vim
vim --clean
bytes written
rm -f foo
zpty -b hello 'vim --clean'
zpty -w hello ':e foo'
zpty -w hello $'iHello there from foo file\e:w'
while zpty -r hello data; [[ $data != *"B written"* ]]; do sleep 0.1; done
ls foo
zpty -d hello