Zsh 提示仅显示最后一次错误代码
Posted
技术标签:
【中文标题】Zsh 提示仅显示最后一次错误代码【英文标题】:Zsh prompt showing last error code only once 【发布时间】:2018-03-18 11:49:30 【问题描述】:我希望我的提示在上一个命令失败时显示一个叉号 (✘)。我使用以下代码:
export PROMPT=$'%(?..✘\n)\n› '
这给了我以下输出:
› echo Hello
Hello
› asjdfiasdf
zsh: command not found: asjdfiasdf
✘
›
✘
我想对提示进行修改,使其在Enter后重绘提示时不重复打叉(上例中的第三种情况)。
有可能吗?
【问题讨论】:
你使用 bash 还是 zsh? Zsh。 @TarunLalwani 编辑了标签并添加了 bash。我不认为这是一个合适的标签。 @MariánČerný,我添加该标签的原因是,这个问题可能需要使用 bash 的人的专家评论,并且该解决方案可能适用于 bash 和 zsh。只是为了确保专家不会错过它,我这样做了 @TarunLalwani 谢谢。你有更高的声誉,所以我相信你的决定。 @TarunLalwani – 我认为 bash 关键字在这里没有任何意义。由于 bash 使用$PROMPT_COMMAND
而 zsh 使用 preexec()
和 precmd()
,因此没有适用于两者的解决方案。
【参考方案1】:
我想我明白了。如果您发现错误,请告诉我...
preexec()
preexec_called=1
precmd()
if [ "$?" != 0 ] && [ "$preexec_called" = 1 ]
then echo ✘; unset preexec_called; fi
PROMPT=$'\n› '
结果:
› ofaoisfsaoifoisafas
zsh: command not found: ofaoisfsaoifoisafas
✘
›
› echo $? # (not overwritten)
127
【讨论】:
不错。我之前没有尝试过preexec
。奇迹般有效。我稍微更新了您的代码,因此没有 ret
变量。并添加了一个换行符。
如果你想让十字架变成红色,使用:echo "$fg_bold[red]✘$reset_color"
参考 9.3.1 挂钩函数:zsh.sourceforge.net/Doc/Release/Functions.html,所有此类函数的列表:zsh.sourceforge.net/Doc/Release/Functions-Index.html【参考方案2】:
我在我的 zsh 中执行此操作,但使用颜色而不是 unicode 字符。原理是一样的。
首先,我设置我的颜色,确保它们仅在受支持时使用:
case $TERM in
( rxvt* | vt100* | xterm* | linux | dtterm* | screen )
function PSC() echo -n "%\e[$*m%"; # insert color-specifying chars
ERR="%(0?,`PSC '0;32'`,`PSC '1;31'`)" # if last cmd!=err, hash=green, else red
;;
( * )
function PSC() true; # no color support? no problem!
ERR=
;;
esac
接下来,我设置了一个神奇的回车功能(感谢this post about an empty command(忽略问题,看我这里如何改编):
function magic-enter() # from https://superuser.com/a/625663
if [[ -n $BUFFER ]]
then unset Z_EMPTY_CMD # Enter was pressed on an empty line
else Z_EMPTY_CMD=1 # The line was NOT empty when Enter was pressed
fi
zle accept-line # still perform the standard binding for Enter
zle -N magic-enter # define magic-enter as a widget
bindkey "^M" magic-enter # Backup: use ^J
现在是解释捕获命令并使用其返回码设置提示颜色的时候了:
setopt prompt_subst # allow variable substitution
function preexec() # just after cmd has been read, right before execution
Z_LAST_CMD="$1" # since $_ is unreliable in the prompt
#Z_LAST_CMD="$1[(wr)^(*=*|sudo|-*)]" # avoid sudo prefix & options
Z_LAST_CMD_START="$(print -Pn '%D%s.%.')"
Z_LAST_CMD_START="$Z_LAST_CMD_START%." # zsh <= 5.1.1 makes %. a literal dot
Z_LAST_CMD_START="$Z_LAST_CMD_START%[%]" # zsh <= 4.3.11 makes %. literal
function precmd() # just before the prompt is rendered
local Z_LAST_RETVAL=$? # $? only works on the first line here
Z_PROMPT_EPOCH="$(print -Pn '%D%s.%.')" # nanoseconds, like date +%s.%N
Z_PROMPT_EPOCH="$Z_PROMPT_EPOCH%." # zsh <= 5.1.1 makes %. a literal dot
Z_PROMPT_EPOCH="$Z_PROMPT_EPOCH%[%]" # zsh <= 4.3.11 makes %. a literal %.
if [ -n "$Z_LAST_CMD_START" ]; then
Z_LAST_CMD_ELAPSED="$(( $Z_PROMPT_EPOCH - $Z_LAST_CMD_START ))"
Z_LAST_CMD_ELAPSED="$(printf %.3f "$Z_LAST_CMD_ELAPSED")s"
else
Z_LAST_CMD_ELAPSED="unknown time"
fi
# full line for error if we JUST got one (not after hitting <enter>)
if [ -z "$Z_EMPTY_CMD" ] && [ $Z_LAST_RETVAL != 0 ]; then
N=$'\n' # set $N to a literal line break
LERR="$N$(PSC '1;0')[$(PSC '1;31')%D%Y/%m/%d %T$(PSC '1;0')]"
LERR="$LERR$(PSC '0;0') code $(PSC '1;31')$Z_LAST_RETVAL"
LERR="$LERR$(PSC '0;0') returned by last command"
LERR="$LERR (run in \$Z_LAST_CMD_ELAPSED):$N"
LERR="$LERR$(PSC '1;31')\$Z_LAST_CMD$(PSC '0;0')$N$N"
print -PR "$LERR"
fi
最后设置提示:
PROMPT="$(PSC '0;33')[$(PSC '0;32')%n@%m$(PSC '0;33') %~$PR]$ERR%#$(PSC '0;0') "
它的外观如下:
对问题的更直接的回答,改编自上文:
function magic-enter() # from https://superuser.com/a/625663
if [[ -n $BUFFER ]]
then unset Z_EMPTY_CMD # Enter was pressed on an empty line
else Z_EMPTY_CMD=1 # The line was NOT empty when Enter was pressed
fi
zle accept-line # still perform the standard binding for Enter
zle -N magic-enter # define magic-enter as a widget
bindkey "^M" magic-enter # Backup: use ^J
function precmd() # just before the prompt is rendered
local Z_LAST_RETVAL=$? # $? only works on the first line here
# full line for error if we JUST got one (not after hitting <enter>)
if [ -z "$Z_EMPTY_CMD" ] && [ $Z_LAST_RETVAL != 0 ]; then
echo '✘'
fi
PROMPT=$'\n› '
屏幕截图:
【讨论】:
我不小心在第一个屏幕截图的 prompt.zsh 源代码中包含了最后一行RPROMPT="$(PSC '0;34')%w %*$(PSC '0;0')"
。当我从我在这里发布的内容中删除它时,我没有注意到它在那里,因为它不相关。
很高兴知道还有其他选择。我以前见过一些小部件和绑定。以我目前的 zsh 知识,我发现 @sneep 的解决方案更容易理解。顺便说一句,我的 Unicode 交叉字符使用红色:-D。【参考方案3】:
使用 prexec 和 precmd 钩子:
在任何命令执行之前调用 preexec 钩子。没有执行命令时不会调用它。例如,如果您在空提示符或只有空格的提示符处按 Enter,则不会调用它。调用此钩子表示命令已运行。
在显示提示之前调用 precmd 钩子以收集下一个命令。在打印提示之前,您可以打印出退出状态。在这里我们可以检查一个命令是否刚刚执行,以及是否有我们想要显示的状态码。
这与@sneep 建议的解决方案非常相似,这也是一个很好的解决方案。不过,使用这些钩子是值得的,这样如果您有其他任何东西注册这些钩子,他们也可以这样做。
# print exit code once after last command output
function track-exec-command()
zsh_exec_command=1
function print-exit-code()
local -i code=$?
(( code == 0 )) && return
(( zsh_exec_command != 1 )) && return
unset zsh_exec_command
print -rC1 -- ''$(%):-"%F160✘ exit status $code%f"''
autoload -Uz add-zsh-hook
add-zsh-hook preexec track-exec-command
add-zsh-hook precmd print-exit-code
【讨论】:
以上是关于Zsh 提示仅显示最后一次错误代码的主要内容,如果未能解决你的问题,请参考以下文章
VSCODE 构建错误`终端进程“/bin/zsh '-c', 'yarn run watch-extensionsd'”无法启动(退出代码:127)。
jQuery-UI 对话框仅显示 for 循环的最后一次迭代 [重复]