我知道 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。这些都是例子。我希望它适用于每个命令。
不能有任何预显示挂钩,因为当命令将某些内容输出到终端或任何其他文件时,根本不涉及 shell。
\n\n该钩子必须位于由命令行启动的任何进程或线程对向 tty 设备打开的文件描述符进行第一次写入系统调用时运行的命令中。或者您必须使用某种 IPC 机制重定向命令的 stdout 和 stderr (可能必须是伪 tty 对,以便最大限度地减少对命令行为的影响),并在收到某些内容时Output:
插入xc2\xb9。无论如何,这将是相当复杂且相当具有侵入性的。
现在,这不是我会做的事情,但你可以尝试这样的事情:
\n\npreexec() {\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
.
在下一个提示之前,再次查询光标位置,如果它没有移动,则将光标移回行首,以便下一个提示覆盖该位置Output:
。我们禁用promptsp
它,因为它会干扰这一点。
expect
\xc2\xb9这种基于 pty 的方法可以通过以下方式实现:
#! /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