检测上一行是否是命令

检测上一行是否是命令

我想启用Windows 终端外壳集成在bash中。 (不要评判我。)一个很好的功能是终端可以在每个命令的滚动条中显示一个标记,其颜色取决于命令执行是否成功。但是,如果没有执行任何命令(空行、Ctrl-C...),则颜色应保持中性。

这是通过在提示中放置特殊的转义序列来实现的。我当前提示的简化版本如下:

PS1="\[\e]133;D;\$?\a\] \$ \[\e]133;B\a\]"

在那里,\e]133;D;\$?\a标记上一个命令的结束,并;\$?包括最后的返回代码,让终端知道它是如何结束的。 (并\e]133;B\a标记提示的结束。)我想不是;\$?如果先前的输入不是命令,则包括(再次:空行,Ctrl-C...)。

有没有办法检测这种情况?

上面链接的文档提供了 PowerShell 的解决方案,但我不知道如何将其应用到 bash。 PowerShell 为每个历史记录条目保留一个唯一的 ID,并且在显示每个提示之前,会用一些逻辑更新全局变量。另一方面,据我所知,bash 不保留这样的 id。

如果你有 zsh 的解决方案,我也会采纳。

答案1

以下代码适用于 Bash 5.2.15:

_debug() { [ "$BASH_COMMAND" != _prompt_command ] && SHOW_STATUS=1; }
_prompt_command() { STATUS=";$?"; [ -z "$SHOW_STATUS" ] && STATUS=; SHOW_STATUS=; }
PROMPT_COMMAND=_prompt_command
trap _debug DEBUG
PS1="\$STATUS \$ "

这是一个概念证明,一个可以合理区分命令和非命令并相应地包含;\$?在提示中或不包含在提示中的装置。它之所以有效,是因为DEBUG陷阱不是由非命令触发的。

不幸的是,像这样的子 shell(echo foo)不会触发陷阱;显式子 shell 的管道也不会(例如(echo foo) | (cat))。这是我的解决方案的缺陷。尽管如此,这样的命令在交互式 shell 中可能很少见(我知道它们在我的工作流程中极其罕见),所以希望您会认为这个缺陷很小。

对于您来说,定义行PS1应该是:

PS1="\[\e]133;D\$STATUS\a\] \$ \[\e]133;B\a\]"

但我无法在 Windows 终端中测试它。

相关内容