ZSH 是否有 postexec/predisplay 挂钩?

Edd*_* Jr 5 zsh

我知道 zsh 有一个 preexec 钩子,它会在命令执行之前触发,但是是否有一个在命令启动后但在输出显示到屏幕之前触发的钩子?我问是因为我想根据是否有/将有实际输出来显示一些东西。

例如:
cd dir不输出任何东西
ls dir输出东西

在那个例子中,我想显示:Output:\n在 ls 目录显示之前而不是在cd运行时显示,因为它没有显示。我希望它看起来像:

~ $: cd dir
~/dir $: ls .
Output:
total 464
drwxr-xr-x+  55 eddie  staff   1.8K May  2 11:07 .
drwxr-xr-x    6 root   admin   204B Apr 22 13:48 ..
~/dir $
Run Code Online (Sandbox Code Playgroud)

我不只是想包装 cd 和 ls。这些都是例子。我希望它适用于每个命令。

Sté*_*las 5

不能有任何预显示挂钩,因为当命令将某些内容输出到终端或任何其他文件时,根本不涉及 shell。

\n\n

该钩子必须位于由命令行启动的任何进程或线程对向 tty 设备打开的文件描述符进行第一次写入系统调用时运行的命令中。或者您必须使用某种 IPC 机制重定向命令的 stdout 和 stderr (可能必须是伪 tty 对,以便最大限度地减少对命令行为的影响),并在收到某些内容时Output:插入xc2\xb9。无论如何,这将是相当复杂且相当具有侵入性的。

\n\n

现在,这不是我会做的事情,但你可以尝试这样的事情:

\n\n
preexec() {\n  printf \'%-*s\' $COLUMNS "Output:"\n  read -sdR $\'pos_before?\\e[6n\'\n}\n\nprecmd() {\n  read -sdR $\'pos_after?\\e[6n\'\n  [[ $pos_after != $pos_before ]] || printf \'\\r\'\n}\nset +o promptsp\n
Run Code Online (Sandbox Code Playgroud)\n\n

也就是说,在运行命令输出之前Output:,将光标移动到屏幕的右边缘(因此,如果有的话,下一个写入的内容将位于下一行的开头),并将当前光标位置记录在$pos_before.

\n\n

在下一个提示之前,再次查询光标位置,如果它没有移动,则将光标移回行首,以便下一个提示覆盖该位置Output:。我们禁用promptsp它,因为它会干扰这一点。

\n\n
\n\n

expect\xc2\xb9这种基于 pty 的方法可以通过以下方式实现:

\n\n
#! /usr/bin/expect -f\n\nset x 0\nset timeout -1\nstty raw -echo\nlog_user 0\nspawn -noecho zsh\n\n# tell zsh to send a special sequence before the prompt (precmd)\n# and a different one before each command (preexec)\nsend {precmd() printf "\\1\\1"; preexec() printf "\\2\\2";set +o promptsp}\nsend "\\r"\n\n# wait for the second prompt\nexpect "\\1\\1"\n\n# set our x flag when the preexec string has been output and reset\n# it upon precmd. write "Output:" if some character is received while\n# the flag is up.\nexpect {\n  -re "^\\2\\2" {\n    set x 1; exp_continue\n  }\n  -re "^\\1\\1" {\n    set x 0; exp_continue\n  }\n  -re "^.\\[^\\1\\2\\]*" {\n    if {$x} {send_user "Output:\\n"; set x 0}\n    send_user -- "$expect_out(buffer)"\n    exp_continue\n  }\n\n  -i $user_spawn_id -re .+ {\n   send -- $expect_out(buffer); exp_continue\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n