Detect if the previous line was a command or not

I’d like to enable Windows terminal shell integration in bash. (Don’t judge me.) One nice feature is that the terminal can show a mark in the scrollbar for each command, with a color depending on whether the command executed was successful or not. However, if no command is executed (empty line, Ctrl-C…) then the color should remain neutral.

This is achieved by putting special escape sequences in the prompt. A simplified version of my current prompt is the following:

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

There, e]133;D;$?a marks the end of the previous command, and the ;$? includes the last return code to let the terminal know how it ended. (And e]133;Ba marks the end of the prompt.) I’d like to not include the ;$? if the previous input was not a command (again: blank line, Ctrl-C…).

Is there a way to detect this situation?

The documentation linked above provides a solution for PowerShell, but I don’t see how to apply it to bash. PowerShell keeps a unique id for each history entry, and before each prompt is displayed, a little bit of logic updates a global variable with it. On the other hand, as far as I know, bash doesn’t keep such ids.

If you have a solution for zsh, I’ll also take it.

Asked By: N.I.


The following code works in Bash 5.2.15:

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

This is a proof of concept, a contraption that reasonably tells commands from non-commands and accordingly includes ;$? in the prompt or not. It works because the DEBUG trap is not triggered by non-commands.

Unfortunately a subshell like (echo foo) does not trigger the trap; neither does a pipeline of explicit subshells (e.g. (echo foo) | (cat)). This is a flaw of my solution. Still such commands are probably rare in interactive shells (I know they are extremely rare in my workflow), so hopefully you will consider the flaw minor.

For you the line defining PS1 should be:

PS1="[e]133;D$STATUSa] $ [e]133;Ba]"

but I have no means to test it in Windows Terminal.

Answered By: Kamil Maciorowski
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.