Bash Prompt with Last Exit Code

后端 未结 7 1713
余生分开走
余生分开走 2020-11-30 22:12

So, I\'ve been trying to customize by bash prompt so that it will look like

[feralin@localhost ~]$ _

with colors. I managed to get constant

相关标签:
7条回答
  • 2020-11-30 22:44

    To preserve original prompt format (not just colors), you could append following to the end of ~/.bashrc:

    PS1_ORIG=$PS1 # original primary prompt value
    PROMPT_COMMAND=__update_prompt # Func to be re-evaluated after each command is executed
    __update_prompt() {
        local PREVIOUS_EXIT_CODE="$?"
        if [ $PREVIOUS_EXIT_CODE != 0 ]; then
            local RedCol='\[\e[0;31m\]'
            local ResetCol='\[\e[0m\]'
            local replacement="${RedCol}\u${ResetCol}"
    
            # Replace username color
            PS1=${PS1_ORIG//]\\u/]$replacement}
            ## Alternative: keep same colors, append exit code
            #PS1="$PS1_ORIG[${RedCol}error=$PREVIOUS_EXIT_CODE${ResetCol}]$ "
        else
            PS1=$PS1_ORIG
        fi
    }
    

    See also the comment about the alternative approach that preserves username color and just appends error code in red to the end of original prompt format

    0 讨论(0)
  • 2020-11-30 22:45

    Improved @demure

    I think this is important because there is not always exit status is 0 or 1.

    if [ $EXIT != 0 ]; then
        PS1+="${Red}${EXIT}:\u${RCol}"      # Add red if exit code != 0
    else
        PS1+="${Gre}${EXIT}:\u${RCol}"      # Also displays exit status
    fi
    
    0 讨论(0)
  • 2020-11-30 22:48

    If you don't want to use the prompt command there's two things you need to take into account:

    1. getting the value of $? before anything else, otherwise it'll be overriden
    2. escaping all the $'s in the PS1 (so it's not evaluated when you assign it)

    Working example using a variable

    PS1="\$(VALU="\$?" ; echo \$VALU ; date ; if [ \$VALU == 0 ]; then echo zero; else echo nonzero; fi) " 
    

    Working example without a variable

    Here the if needs to be the first thing, before any command that would override the $?.

    PS1="\$(if [ \$? == 0 ]; then echo zero; else echo nonzero; fi) "
    

    Notice how the \$() is escaped so it's not executed right away but each time PS1 is used. Also all the uses of \$?

    0 讨论(0)
  • 2020-11-30 22:58

    Why i didn't think about that myself?) I found this very interesting and add this feature to my 'info-bar' project. Eyes will turn red if last command failed.

    #!/bin/bash
    eyes=(O o ∘ ◦ ⍤ ⍥) en=${#eyes[@]} mouth='_'                                                           
    face () { # gen random face                                                                           
        [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW                                                  
        if [[ $1 ]]; then printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}"                       
                     else printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"  
        fi                                                                                                
    }                                                                                                     
    info () { error=$?                                                                                    
        [[ -d .git ]] && {  # If in git project folder add git status to info bar output                  
            git_clr=('GIT' $(git -c color.ui=always status -sb)) # Colored output 4 info                  
            git_tst=('GIT' $(git                    status -sb)) # Simple  output 4 test                  
        }                                                                                                 
        printf -v line "%${COLUMNS}s"                            # Set border length                      
        date=$(printf "%(%a %d %b %T)T")                         # Date & time 4 test                     
        test=" O_o $PWD  ${git_tst[*]} $date o_O "               # Test string                            
        step=$[$COLUMNS-${#test}]; [[ $step -lt 0 ]] && step=0   # Count spaces                           
        line="$GRN${line// /-}$DEF\n"                            # Create lines                           
        home="$BLD$BLU$PWD$DEF"                                  # Home dir info                          
        date="$DIM$date$DEF"                                     # Colored date & time                    
               #------+-----+-------+--------+-------------+-----+-------+--------+                       
               # Line | O_o |homedir| Spaces | Git  status | Date|  o_O  |  Line  |                       
               #------+-----+-------+--------+-------------+-----+-------+--------+                       
        printf "$line $(face) $home %${step}s ${git_clr[*]} $date $(face) \n$line" # Final info string    
    }                                                                                                     
    PS1='${debian_chroot:+($debian_chroot)}\n$(info)\n$ '                                                 
    case "$TERM" in xterm*|rxvt*)                                                                         
        PS1="\[\e]0;${debian_chroot:+($debian_chroot)} $(face 1) \w\a\]$PS1";;                            
    esac 
    

    0 讨论(0)
  • 2020-11-30 23:06

    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 ran after each command to generate the prompt.

    You could try the following in your ~/.bashrc

    PROMPT_COMMAND=__prompt_command # Func to gen 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 line 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.

    0 讨论(0)
  • 2020-11-30 23:06

    I wanted to keep default Debian colors, print the exact code, and only print it on failure:

    # Show exit status on failure.
    PROMPT_COMMAND=__prompt_command
    
    __prompt_command() {
        local curr_exit="$?"
    
        local BRed='\[\e[0;91m\]'
        local RCol='\[\e[0m\]'
    
        PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
    
        if [ "$curr_exit" != 0 ]; then
            PS1="[${BRed}$curr_exit${RCol}]$PS1"
        fi
    }
    
    0 讨论(0)
提交回复
热议问题