zsh zpty 不能在 macOS 上运行,可以在 Linux 上运行吗?

zsh zpty 不能在 macOS 上运行,可以在 Linux 上运行吗?

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 更好。

  1. 您向 vim 发送命令,并且从不等待它做出反应。因此很有可能foo最终会出现,但 zsh 速度更快,并且会在文件准备好之前进行检查。这取决于 vim 与 zsh 的相对执行速度,这可能取决于各自的确切版本、系统库、操作系统内核、CPU、月相等。
  2. 您从不从终端读取数据,因此 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

相关内容