.bashrc and PS1 for productivity

Finely tuned bash UNIX shell can really help streamline the workflow.

Besides general tricks akin

HISTFILESIZE=6000
HISTSIZE=4000
command_oriented_history=1
HISTCONTROL=ignoreboth

…and common aliases

alias   vt100='TERM=vt100'
alias   a=alias
alias   h='history 18'
alias   r='fc -s'
alias   l='ls -AF'
alias   m=less
alias   g='grep -d skip'
alias   j=jobs

…and some functionality ultimately requiring shell functions

function s()    { du -sk "$@" | sort -nr | $PAGER ; }
[ "`type -t ll`" = alias ] && unalias ll
ll()    { ls -l "$@" | $PAGER_E ; }
lld()   { ls -Al "$@" | grep -e ^d -e ^l | $PAGER_E ; }
#ff()   { find . -type f -name "*$2" -exec egrep -l "$1" {} \; | $PAGER_E ; }
ff() {
        find . -type f \! -size +1000000c \
                -name "*$2" \! -name "*.[ao]" \! -name "*.mp3" \
                -exec egrep -l "$1" {} \; |
        $PAGER_E
}
te()    { nedit "$@" & }

…as well as some system-dependent aliases/funcs:

# System dependant
case "$OSTYPE" in
        *[bB][sS][dD]*)
                alias   p='ps uxwOvy | cut -c10-'
                alias   n='netstat -f inet'
                psg()   { ps auxw | grep [^]]"$*"; }
                alias   mc='midc -u -c'
                # allowing cyr display on freebsd
                export LC_CTYPE=ru_RU.KOI8-R
        ;;
        *[lL]inux*)
                alias   p='ps -lu $USER'        # ???
                alias   n='netstat -Ainet -o'
                psg()   { ps auxw | grep [^]]"$*"; }
        ;;
        *) # SYSV (?)
                alias   p='ps -lu $USER'        # SYSV
        ;;
esac

the huge portion of my ~/.bashrc file is dedicated to The Prompt: PS1.

The tiniest ever PS1, consisting of only a simple dollar sign (with a space appended, of course)

$ 

leaves the command line pretty uncluttered.

What for?

Simple.

Command line space (like any other space on a computer screen) is limited, usually by 80 characters. And even if you can enlarge your terminal to 132 chars wide or something, it’s easier to work with narrower text columns.
Have you noticed how 2-column books are much easier to read compared to 1-column ones? Guess you know what I mean.

The generic shell prompt out of the box on systems from many vendors consists of username, hostname and cwd or current working directory. This may be useful for novice UNIX users and even may be positively familiar to MS Windows users, but the prompt gets longer the further away from $HOME you go. It’s not unusual to see the command’s initial cursor’s position in the middle of the screen horizontally on way too many “system operators” workstations.

Also it becomes annoying when you advance in your UNIX administration practice and inevitably find yourself typing longer commands.

Especially when those commands are longer (much longer!) than what your default clunky prompt set by the system vendor leaves you with.

For e.g. one of the longest command lines in my current .bash_history is this:


for d in 1 2; do for p in 1 2 3 4 5 6; do id3tag -a "Igor Kalinin" -A "Fares - Covenants" -c "Rec'd by Alexander Stcheblikin via self-made stereo mic” -y 2006 -s “Covenants day $d - part $p” /opt/music/events/Fares/060116-Fares-Covenants-Igor_Kalinin/Covenants$d-$p.mp3; done; done &

This is of course one of the most extreme, but you get the idea: the longer you work in UNIX, the longer the commands you type. Well, at least from time to time it is such :)
BTW that command was extracted with the help of this one:

g -v ssh .bash_history | perl -e 'print((sort{length $a <=> length $b}<>)[-1])’

which is (not) surprisingly a more-common length and note that it pretty much fits on a screen’s width!
(here g -v ssh filters out all commands from the history containing “ssh” in them)

- except when your prompt has already taken half the screen…

So it seems a wise go to move all the so “important” info (hostnames/paths/usernames/who-knows-what) out of sight, preferably somewhere it is not lost completely.

I’d note here, that that “info” may be lost without any significant “loss” to the operator. Any good system operator should have enough good short-term memory in their brains to hold all of this. Besides, this info (plus useful extra) is easily remindable by typing

id; pwd; hostname

However, the GUI (which older system operators lacked) gives us one great benefit: the xterm’s titlebar, which, in my case, displays something like this:

username@hostname /working_directory

This isn’t just a handy reminder freeing up a bit of our brain RAM, yet more importantly it is a nifty identifier for a GUI window holding the xterm application. So instead of three dozens anonymous windows titled “xterm” you can have a neat list of remote (and local) sessions possibly sorted by machine name or username.

Now you might rightfully ask: all that is fine and everything, but what is it that here in 21st century we refuse the clever dynamic shell prompt introduced ages ago?

Well, seems to me the most elegant way to combine brevity with dynamism in a shell prompt would be to use dynamic feature to indicate special (i.e. rare) situations and not something lame like clock or PID (do you really need to know e.g. since when your command prompt is waiting for your input? as for me, the concept of “wall clock time” is totally irrelevant in the UNIX world…)

For example such a situation could be the exit code of the program last ran - when it actually failed.

And that’s about it for now. What follows is the complete .bashrc incorporating the thoughts described plus some [shell] comments which hopefully will help you to grasp the concepts.


# WARNING! this file is not sourced if bash is invoked as sh !

[ -r ~/.bashrc-local ] && . ~/.bashrc-local

HISTFILESIZE=6000
HISTSIZE=4000
command_oriented_history=1
HISTCONTROL=ignoreboth

###
### Prompt Start, (also $HISTFILE may be set here)
###
#
# The prompt is devided to 2 parts: “floating” & “static”.
# “floating” part can be displayed on either command prompt itself,
# or on the titlebar of the xterm
# “static” part is always displayd (or not displayd) on command prompt.
#

_TTY_SHORT=$(tty|sed -e s:/dev/:: -e s:tty::)

# Don’t display hostname but tty for local/login shell
[ -n "$DISPLAY" -o ${#_TTY_SHORT} -eq 1 ] && {
FLOAT_PROMPT_USER_TTY_HOST=$USER’@(’$_TTY_SHORT’)’

[ -d $HOME/.bash_history.d ] && {
HISTFILE=$HOME/.bash_history.d/$(basename `tty`)
[ -e $HISTFILE ] || touch $HISTFILE
}
} || {
FLOAT_PROMPT_USER_TTY_HOST=$USER\@`hostname -s`
}

case $TERM in
*xterm*|dtterm)
# we cant use PS1 escapes in echoing to xterm titlebar

#PROMPT_TITLEBAR=’\[\033]0;\u@${_TTY_SHORT} \w\007\]’
#echo -ne “\033]0;$USER@${_TTY_SHORT}\007″
cd () {
command cd “$@”
echo -ne “\033]0;$FLOAT_PROMPT_USER_TTY_HOST $PWD\007″
}
CMD_PROMPT=”
cd .
;;
*)
#PROMPT_TITLEBAR=
CMD_PROMPT=$FLOAT_PROMPT_USER_TTY_HOST’ \w’
;;
esac

PROMPT_COMMAND=\
‘mySTAT=$?
if [ $mySTAT != 0 ]; then
PROMPT_STATUS=\<$mySTAT\>
else
PROMPT_STATUS=
fi’

PS1_DFL=${CMD_PROMPT}’${PROMPT_STATUS}\$ ‘

PS1_MAX=\
${PROMPT_TITLEBAR}\
‘\t|’${FLOAT_PROMPT_USER_TTY_HOST}’ \w’\
‘${PROMPT_STATUS}’\
‘>$SHLVL<\$ '

#PS1=`tty|sed s/[/]dev[/]//`'[\#]\w\$ '
PS2=' '

function PS() {
case $1 in
0) PS1='\$ ' ;;
1) PS1='${PROMPT_STATUS}\$ ' ;;
[2-9]) PS1=$PS1_MAX ;;
*) PS1=$PS1_DFL ;;
esac
}

PS

###
### Prompt End
###

export PAGER=less
# On freebsd man quits @ eof, hence '-e'.
export LESS='-eMis'
export LESSOPEN="|lesspipe.sh %s"
# This pager quits-on-eof
PAGER_E='less -EX'
# ...still on linux -X is very much desired for 'man', though it disables arrows :(
# aliases
alias vt100='TERM=vt100'
alias a=alias
alias h='history 18'
alias r='fc -s'
alias l='ls -AF'
alias m=less
alias g='grep -d skip'
alias j=jobs
function s() { du -sk "$@" | sort -nr | $PAGER ; }

alias d=dirs
alias pd='pushd .'
alias pd2='pushd +2'
alias po=popd

# pseudo-aliases, i.e. functions
[ "`type -t ll`" = alias ] && unalias ll
ll() { ls -l "$@" | $PAGER_E ; }
lld() { ls -Al "$@" | grep -e ^d -e ^l | $PAGER_E ; }
ff() {
find . -type f \! -size +1000000c \
-name "*$2" \! -name "*.[ao]" \! -name "*.mp3" \
-exec egrep -l "$1" {} \; |
$PAGER_E
}
te() { nedit "$@" & }

# For reading russian msgs in mutt :( unset LC_ALL
unset LC_COLLATE LC_CTYPE LC_ALL
export LESSCHARSET=koi8-r

# System dependant
case "$OSTYPE" in
*[bB][sS][dD]*)
alias p='ps uxwOvy | cut -c10-'
alias n='netstat -f inet'
psg() { ps auxw | grep [^]]"$*"; }
alias mc='midc -u -c'
# allowing cyr display on freebsd
export LC_CTYPE=ru_RU.KOI8-R
;;
*[lL]inux*)
alias p='ps -lu $USER' # ???
alias n='netstat -Ainet -o'
psg() { ps auxw | grep [^]]"$*"; }
;;
*) # SYSV (?)
alias p='ps -lu $USER' # SYSV
;;
esac

# other conveniences
#notify=1

PATH=$HOME/bin:$PATH:/usr/local/sbin



Subscribe to New stories via RSS
Also on STEREO:

Leave a Reply