[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Pimp your shell - Debian developer tips?



Hello world,

Like Paul said in his reply, I also have a "bash monstrosity" as a
Bash prompt. I last spent time tweaking it many years ago, so... This
migh reflect what my head was like in the past, not today :-]

I am attaching here the relevant portion of my .bashrc

> Basically the only improvements over lesser distributions we have are:
> * color: it's not for mere looks, but it visually separates output of
>   commands between themselves
> * full path from ~ (Fedora has only the last component which sucks)

I do consider this to be very important for me. I'm not inlining it
here, as mine is quite verbose, but the colors are defined in
promptFunc(). I don't really follow what you mean by "full path from
~" — Isn't it what \w produces?

> I would like to add at minimum:
> * current git branch (but not -dirty as that can take ages on large repos
>   on slow media -- you want changing directory to be instant)

Yes, I have all this set. I remember it being somewhat slow on large
repos, but I seldom notice it anymore (and on an SSD, it's seldom more
than a couple of seconds on a large Git tree that's not cached). Today
I see this as a heavy number of calls to git, and it always calls git
even if not in a git tree, but... Whatever ☺ This is defined in
parse_git_branch()

> * result of the last command

Yes, I find this to be tremendously useful. I don't absolutely like
the way I handle this (see LAST_RET at the beginning of prompt_func)

> Also, for people who use _many_ terminal tabs while logged on to _many_
> machines like me, I'd also suggest window title.  To simplify the code I've
> personally added parsing this sequence to Linux kernel (as of 3.16).
> I also put the title in ALL UPPERCASE if it's a root session, this helps
> while doing admin tasks.  There's no space for username so I give only
> machine name.

Makes sense. My window title was meant to reflect the previous command
run. But it reflects the last command that _finished_, amd that's not
always immediate.

I also print my regular username in green, but a root login is
presented in red (not only due to the '$' vs. '#' component).

> > I've read a bit on zsh and powerline and the like, but I am annoyed that
> > all those blog posts are quite superficial and do not mention security,
> > interoperability or performance aspects. Frankly any blog post that
> > recommends cloning random repos or even worse, running wget | sh something
> > gives me chills.
> 
> Aye.  Just bash in bashrc should be enough, without iffy Python daemons or
> similar stuff.

I agree. The code I'm sharing here is far from optimal, but it's easy
to follow (after... 5-10 years from its last modification.

> As for powerline: it's not in Unicode, and even worse, illegally uses code
> points that have since been assigned for something else.  Another version of
> powerline uses PUA characters, but also with ill-chosen codepoints that
> clash with popular assignments (CSUR, MUFI).

I'm not aware of Powerline, so I won't comment on it.

> Another thing I've tried but rejected is writing some stuff on the right
> edge of the screen.  This is easy to code and looks good, but causes nasty
> unaligned leftovers if you paste pieces of your console that include the
> prompt, with you not noticing until after the paste is done.

Agree completely.

So, without further ado, my prompt follows:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# Useful to know where we stand while using different version control systems
parse_git_branch() {
    # Yes, temporary, dirty, yada yada yada. Works for me™.
    # --exclude-standard does not exist on git <= 1.5
    git_opts='--exclude-standard'
    branch=`git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'`
    if [ ! -z "$branch" ]
    then
	clean=`git status --porcelain`
	if [ ! -z "$clean" ]
	then
	    branch="${branch}*"
	    new=`git ls-files -o $git_opts|wc -l`
	    del=`git ls-files -d $git_opts|wc -l`
	    mod=$(( `git ls-files -m $git_opts|wc -l` - $del ))
	    if [ $mod != 0 ]; then branch="${branch}${mod}M"; fi
	    if [ $new != 0 ]; then branch="${branch}${new}N"; fi
	    if [ $del != 0 ]; then branch="${branch}${del}D"; fi

	fi
    fi
    echo $branch
}

# set a fancy prompt (non-color, unless we know we "want" color)
promptFunc()
{
    LAST_RESULT="$?:$_"
    LAST_RET=${LAST_RESULT/:*/}
    LAST_CMD=${LAST_RESULT/*:/}
    VC_STATUS=`parse_git_branch`
    case "$TERM" in
	screen*|xterm*|rxvt*)
	    COLOR_RED="\[\e[31;40m\]"
	    COLOR_GREEN="\[\e[32;40m\]"
	    COLOR_YELLOW="\[\e[33;40m\]"
	    COLOR_BLUE="\[\e[34;40m\]"
	    COLOR_MAGENTA="\[\e[35;40m\]"
	    COLOR_CYAN="\[\e[36;40m\]"

	    COLOR_RED_BOLD="\[\e[31;1m\]"
	    COLOR_GREEN_BOLD="\[\e[32;1m\]"
	    COLOR_YELLOW_BOLD="\[\e[33;1m\]"
	    COLOR_BLUE_BOLD="\[\e[34;1m\]"
	    COLOR_MAGENTA_BOLD="\[\e[35;1m\]"
	    COLOR_CYAN_BOLD="\[\e[36;1m\]"

	    COLOR_NONE="\[\e[0m\]"

	    TERM_TITLE="\\033]0;"

	    HOST="${COLOR_NONE}@${COLOR_CYAN}\h"
	    DIR="${COLOR_YELLOW}『\#』\w"
	    PROMPT="${COLOR_GREEN_BOLD}\\$ ${COLOR_NONE}"

	    if test ! -z "$VC_STATUS"
	    then
		VC=" ${COLOR_CYAN}($VC_STATUS)${COLOR_NONE}"
	    else
		VC=
	    fi
    
	    if test `whoami` != "root"
		then
		USERNAME="${COLOR_GREEN}\u"
	    else
		USERNAME="${COLOR_RED}\u"
	    fi

	    if test $LAST_RET -eq 0
	    then
		STATUS="${LAST_RET}"
	    else
		STATUS="${COLOR_RED_BOLD}${LAST_RET}${COLOR_NONE} "
	    fi
	    ;;
	*)
	    STATUS=$LAST_RET
	    USERNAME="\u"
	    HOST="@\h"
	    COUNT="[\#]"
	    DIR="\w"
	    PROMPT="\\$ "
	    if test ! -z "$VC_STATUS"
	    then
		VC="($VC_STATUS)"
	    else
		VC=
	    fi
	    ;;
    esac

    PS1="${STATUS}${VC} ${USERNAME}${HOST}${DIR}${PROMPT}"

    # If this is an xterm set the title to user@host:dir
    case "$TERM" in
	screen*|xterm*|rxvt*)
	    echo -ne "${TERM_TITLE}(${LAST_CMD}:${LAST_RET}) ${USER}@${HOSTNAME}: ${PWD/$HOME/~}\\007"
	    ;;
    esac
}

PROMPT_COMMAND=promptFunc


Reply to: