Bash Prompt With the Last Exit Code

Bash prompt with the last exit code

As you are starting to border on a complex PS1, you might consider using PROMPT_COMMAND. With this, you set it to a function, and it will be run after each command to generate the prompt.

You could try the following in your ~/.bashrc file:

PROMPT_COMMAND=__prompt_command    # Function to generate PS1 after CMDs

__prompt_command() {
local EXIT="$?" # This needs to be first
PS1=""

local RCol='\[\e[0m\]'

local Red='\[\e[0;31m\]'
local Gre='\[\e[0;32m\]'
local BYel='\[\e[1;33m\]'
local BBlu='\[\e[1;34m\]'
local Pur='\[\e[0;35m\]'

if [ $EXIT != 0 ]; then
PS1+="${Red}\u${RCol}" # Add red if exit code non 0
else
PS1+="${Gre}\u${RCol}"
fi

PS1+="${RCol}@${BBlu}\h ${Pur}\W${BYel}$ ${RCol}"
}

This should do what it sounds like you want. Take a look a my bashrc's sub file if you want to see all the things I do with my __prompt_command function.

Include non-0 exit codes in the subsequent bash prompt

A little bit of printf abuse:

printf '%.*s' $? $?

How to change bash prompt color based on exit code of last command?

I assume your quoting is not correct. I fiddled a little bit around with this and finally got it working:

$ bash --version
GNU bash, version 4.4.12(3)-release (i686-pc-cygwin)

$ smiley()
> {
> if [ "$?" == "0" ]; then
> echo -e '\e[0;32m:) '
> else
> echo -e '\e[0;31m:( '
> fi
> }

$ PS1="$PS1"'`smiley`'

$ :) rm non-existing
rm: cannot remove 'non-existing': No such file or directory

$ :( echo "Everything fine"
Everything fine

$ :)

I did this on Windows (64 bit) but I guess it should work on Linux (or any other Unix-like) as well.

Notes:

  1. I wrote a function smiley() (a simplified version of your) and checked it by calling it from command line. It worked fine.

  2. I added it to PS1 and it echoed :) in any case. I realized that the bash replacement was already done in assignment of PS1.

  3. Thus, I safed the invocation of smiley by an extra pair of single quotes to defer the invocation until the output of prompt. Now, it works like expected.

  4. Because the questioner required a colored version I made an update. I found the actual solution in this link: SO: How to change the output color of echo in Linux. It's easy to find the necessary terminal escape sequences. The trick is to use echo -e to enable the backslash escaping in echo.

The snapshot below shows how does it look (with colors):

Snapshot of <code>bash</code> with tuned prompt in an <code>xterm</code>

Capturing exit value of previous command in bash prompt

Make a function that generates your prompt, and save $?:

makeprompt() { 
status=$?
echo "$(echo someoutput) $status"
return $status
}

PS1='$(makeprompt) \$ '

This will give you both the output of the command (here echo, but could be git), and the exit status of the previously executed command.

Correct return value in BASH prompt

You do:

..$(__git_ps1)...\`if [[ $? == 0 ]];

The $? is going to be return status of __git_ps1 not the last executed command on command line.

Try saving the exit return value in the first command substitution block right away:

if [ "$color_prompt" = yes ]; then
color_reset=$(tput sgr0)
color_bold=$(tput bold)
color_white=$(tput setaf 7)
color_jobs=$(tput setaf 7)
color_user=$(tput setaf 3)
color_dir=$(tput setaf 4)
color_load=$(tput setaf 5)
color_succeed=$(tput setaf 2)
color_fail=$(tput setaf 1)
sep=$(tput setaf 7)\)
else
color_reset=
color_bold=
color_white=
color_jobs=
color_user=
color_dir=
color_load=
color_succeed=
color_fail=
sep=\) # remove the braces...
fi

# note the quotes - "" expand at setting time, '' expand at runtime
PS1=
PS1+="${color_user}\u${sep}\[\D{%T}\]${sep}${color_reset}"
PS1+='$('
PS1+='ret=$?; ' # first thing we do - save the exit return value
PS1+='__git_ps1; '
PS1+='printf "%s" "'
PS1+="${color_dir}\W${color_reset}${sep}"
PS1+='"; '
PS1+='if ((ret == 0)); then '
PS1+='printf "%s" "'
PS1+="${color_succeed}" # expand variable on assignment side
PS1+='0"; ' # this looks strange. Just print first the color, then $ret...
PS1+='else '
PS1+='printf "%s" "'
PS1+="$color_fail"
PS1+='$ret"; '
PS1+='fi '
PS1+=')'
PS1+="${color_white}${sep}${color_reset}"
PS1+='\$ ' # note - this is *not* "\$ "

Bash and Zsh prompt that ring a bell and do display error code of last command

The command to test $? itself resets $? to the result of the test. You need to save the value you want to display first.

PS1='\n\
$(st=$?; if [[ $st -gt 0 ]]; then printf "\[\033[01;31m\]$st"; tput bel; else printf "\[\033[01;32m\]0"; fi)\
\[\033]0;$PWD\007\] \
\[\033[0;32m\]\u@\h\
\[\033[01;30m\]:\
\[\033[;;33m\]\w\
\[\033[36m\]`__git_ps1`\
\[\033[0m\]\n$ '

I would recommend building up the value of PS1 using PROMPT_COMMAND, instead of embedding executable code. This gives you more flexibility
for commenting and separating any computations you need from the actual
formatting. make_prompt doesn't need quite so many lines, but it's
just a demonstration.

set_title () {
printf '\033]0;%s%s' "$1" "$(tput bel)"
}

make_prompt () {
local st=$?
local c bell
bell=$(tput bel)

# Green for success, red and a bell for failure
if [[ $st -gt 0 ]]; then
c=31
else
c=32 bell=
fi

win_title=$(set_title "$PWD")
git_status=$(__git_ps1)

PS1="\n"
PS1+="\[\e[01;${c}m$bell\]" # exit status color and bell
PS1+=$st
PS1+="\[$win_title\]" # Set the title of the window
PS1+="\[\e[0;32m\]" # Color for user and host
PS1+="\u@\h"
PS1+="\[\e[01;30m\]" # Color for : separator
PS1+=":"
PS1+="\[\e[;;33m\]" # Color for directory
PS1+="\w"
PS1+="\[\e[36m\]" # Color for git branch
PS1+=$git_status
PS1+="\[\e[0m\]" # Reset to terminal defaults
PS1+="\n$ "
}

PROMPT_COMMAND=make_prompt

zsh already has terminal-agnostic escape sequences for adding color.

PROMPT="%B%(?.%F{green}.%F{red}$(tput bel))%?%f%b %F{green}%n@%m%F{black}%B:%b%F{yellow}%~ %f%(!.#.$) "

Why does the exit status check in my Bash prompt function also evaluate to true?

highlightExitCode is getting the exit status of the last command run, which is git_branch while constructing the value of the prompt.

Use PROMPT_COMMAND instead to build a prompt dynamically. In your .bashrc file,

PROMPT_COMMAND=build_prompt

git_branch()
{
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}

highlightExitCode()
{
if [ "$1" -ne 0 ]; then
echo -en '\xf0\x9f\x98\xb1 '
else
echo -en '\xf0\x9f\x98\x80 '
fi
}

build_prompt () {
last_exit=$?
PS1='[\@][\u] [\W]'
PS1+=$(git_branch)
PS1+=" $(highlightExitCode "$last_exit")"
PS1+='\$ '
}

How to change color of prompt from last exit code in ZSH?

As a function, you need to call it, not expand it as a variable. Do that with a command substitution:

PS1="...%{$fg[\$(changecolor)]%}➜%b "

However, there's a lot of bash-like stuff in this prompt that you can replace with simpler, more robust zsh features. First, %F can be used to change the color directly, without using escape codes stored in an array. (Unlike raw escape codes, and like other zsh-defined escape sequences, %F{...} doesn't need to be wrapped in %{...%}.) Second, there is prompt escape specifically for producing one value or another depending on whether the last exit status was 0 or not.

PS1='%B%F{red}[%F{yellow}%n%F{green}@%F{blue}%M '
PS1+='%F{magenta}%~%F{red}] %(?.%F{green}.%F{red})➜%b%f '

%(?.FOO.BAR) expands to FOO if the last command succeeded, BAR otherwise. %f restores the color to the default, regardless of any preceding %F codes.


%(...) is, in fact, more general than just testing the exit code. ? is just one of 20 or so testable conditions. As a silly example, suppose your birthday is coming up on January 18. Here's an escape to put a cake in your prompt on your birthday.

%(0D.%(18d..).)

More information on prompt escape codes can be found in man zshmisc.



Related Topics



Leave a reply



Submit