![zsh zpty 不能在 macOS 上运行,可以在 Linux 上运行吗?](https://linux22.com/image/214953/zsh%20zpty%20%E4%B8%8D%E8%83%BD%E5%9C%A8%20macOS%20%E4%B8%8A%E8%BF%90%E8%A1%8C%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%20Linux%20%E4%B8%8A%E8%BF%90%E8%A1%8C%E5%90%97%EF%BC%9F.png)
zsh 模块 zsh/zpty 似乎在 Apple M1 macOS 机器上运行的 Linux 虚拟机上运行得很好。但同样的方法在 macOS 上不起作用(即使在同一台主机上)。我已经在 macOS 上预装的 zsh 版本/bin/zsh
和从自制软件安装的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(系统完整性保护)相关,我会感到惊讶。
答案1
我想说这是你的代码中的一个错误,这意味着它可能会或可能不会工作。它在 Linux 上适用于您的事实甚至不能保证它也适用于其他人,并且它并不意味着 Linux 比 macOS 更好。
- 您向 vim 发送命令,并且从不等待它做出反应。因此很有可能
foo
最终会出现,但 zsh 速度更快,并且会在文件准备好之前进行检查。这取决于 vim 与 zsh 的相对执行速度,这可能取决于各自的确切版本、系统库、操作系统内核、CPU、月相等。 - 您从不从终端读取数据,因此 vim 在写入时可能会被阻止。是否卡住取决于 vim 想要写入多少(这可能取决于系统库(特别是 Curses)和 terminfo 条目),以及终端接口允许它在终端消耗数据之前写入多少(这取决于在内核上,也许在 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
必须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