Appendix G. A Sample .bashrc File

The ~/.bashrc file determines the behavior of interactive shells. A good look at this file can lead to a better understanding of Bash.

Emmanuel Rouat contributed the following very elaborate .bashrc file, written for a Linux system. He welcomes reader feedback on it.

Study the file carefully, and feel free to reuse code snippets and functions from it in your own .bashrc file or even in your scripts.


Example G-1. Sample .bashrc file

   1 #===============================================================
   2 #
   3 # PERSONAL $HOME/.bashrc FILE for bash-2.05 (or later)
   4 #
   5 # This file is read (normally) by interactive shells only.
   6 # Here is the place to define your aliases, functions and
   7 # other interactive features like your prompt.
   8 #
   9 # This file was designed (originally) for Solaris.
  10 # --> Modified for Linux.
  11 # This bashrc file is a bit overcrowded - remember it is just
  12 # just an example. Tailor it to your needs 
  13 #
  14 #===============================================================
  15 
  16 # --> Comments added by HOWTO author.
  17 
  18 #-----------------------------------
  19 # Source global definitions (if any)
  20 #-----------------------------------
  21 
  22 if [ -f /etc/bashrc ]; then
  23         . /etc/bashrc   # --> Read /etc/bashrc, if present.
  24 fi
  25 
  26 #-------------------------------------------------------------
  27 # Automatic setting of $DISPLAY (if not set already)
  28 # This works for linux and solaris - your mileage may vary....
  29 #-------------------------------------------------------------
  30 
  31 if [ -z ${DISPLAY:=""} ]; then
  32     DISPLAY=$(who am i)
  33     DISPLAY=${DISPLAY%%\!*}
  34     if [ -n "$DISPLAY" ]; then
  35         export DISPLAY=$DISPLAY:0.0
  36     else
  37         export DISPLAY=":0.0"  # fallback
  38     fi
  39 fi
  40 
  41 #---------------
  42 # Some settings
  43 #---------------
  44 
  45 set -o notify
  46 set -o noclobber
  47 set -o ignoreeof
  48 set -o nounset
  49 #set -o xtrace          # useful for debuging
  50 
  51 shopt -s cdspell
  52 shopt -s cdable_vars
  53 shopt -s checkhash
  54 shopt -s checkwinsize
  55 shopt -s mailwarn
  56 shopt -s sourcepath
  57 shopt -s no_empty_cmd_completion
  58 shopt -s histappend histreedit
  59 shopt -s extglob        # useful for programmable completion
  60 
  61 #-----------------------
  62 # Greeting, motd etc...
  63 #-----------------------
  64 
  65 # Define some colors first:
  66 red='\e[0;31m'
  67 RED='\e[1;31m'
  68 blue='\e[0;34m'
  69 BLUE='\e[1;34m'
  70 cyan='\e[0;36m'
  71 CYAN='\e[1;36m'
  72 NC='\e[0m'              # No Color
  73 # --> Nice. Has the same effect as using "ansi.sys" in DOS.
  74 
  75 # Looks best on a black background.....
  76 echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n"
  77 date
  78 if [ -x /usr/games/fortune ]; then 
  79     /usr/games/fortune -s     # makes our day a bit more fun.... :-)
  80 fi
  81 
  82 function _exit()        # function to run upon exit of shell
  83 {
  84     echo -e "${RED}Hasta la vista, baby${NC}"
  85 }
  86 trap _exit 0
  87 
  88 #---------------
  89 # Shell prompt
  90 #---------------
  91 
  92 function fastprompt()
  93 {
  94     unset PROMPT_COMMAND
  95     case $TERM in
  96         *term | rxvt )
  97             PS1="[\h] \W > \[\033]0;[\u@\h] \w\007\]" ;;
  98         *)
  99             PS1="[\h] \W > " ;;
 100     esac
 101 }
 102 
 103 function powerprompt()
 104 {
 105     _powerprompt()
 106     {
 107         LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
 108         TIME=$(date +%H:%M)
 109     }
 110 
 111     PROMPT_COMMAND=_powerprompt
 112     case $TERM in
 113         *term | rxvt  )
 114             PS1="${cyan}[\$TIME \$LOAD]$NC\n[\h \#] \W > \[\033]0;[\u@\h] \w\007\]" ;;
 115         linux )
 116             PS1="${cyan}[\$TIME - \$LOAD]$NC\n[\h \#] \w > " ;;
 117         * )
 118             PS1="[\$TIME - \$LOAD]\n[\h \#] \w > " ;;
 119     esac
 120 }
 121 
 122 powerprompt     # this is the default prompt - might be slow
 123                 # If too slow, use fastprompt instead....
 124 
 125 #===============================================================
 126 #
 127 # ALIASES AND FUNCTIONS
 128 #
 129 # Arguably, some functions defined here are quite big
 130 # (ie 'lowercase') but my workstation has 512Meg of RAM, so .....
 131 # If you want to make this file smaller, these functions can
 132 # be converted into scripts.
 133 #
 134 # Many functions were taken (almost) straight from the bash-2.04
 135 # examples.
 136 #
 137 #===============================================================
 138 
 139 #-------------------
 140 # Personnal Aliases
 141 #-------------------
 142 
 143 alias rm='rm -i'
 144 alias cp='cp -i'
 145 alias mv='mv -i'
 146 # -> Prevents accidentally clobbering files.
 147 
 148 alias h='history'
 149 alias j='jobs -l'
 150 alias r='rlogin'
 151 alias which='type -all'
 152 alias ..='cd ..'
 153 alias path='echo -e ${PATH//:/\\n}'
 154 alias print='/usr/bin/lp -o nobanner -d $LPDEST'   # Assumes LPDEST is defined 
 155 alias pjet='enscript -h -G -fCourier9 -d $LPDEST'  # Pretty-print using enscript
 156 alias background='xv -root -quit -max -rmode 5' # put a picture in the background
 157 alias vi='vim'
 158 alias du='du -h'
 159 alias df='df -kh'
 160 
 161 # The 'ls' family (this assumes you use the GNU ls)
 162 alias ls='ls -hF --color'	# add colors for filetype recognition
 163 alias lx='ls -lXB'		# sort by extension
 164 alias lk='ls -lSr'		# sort by size
 165 alias la='ls -Al'		# show hidden files
 166 alias lr='ls -lR'		# recursice ls
 167 alias lt='ls -ltr'		# sort by date
 168 alias lm='ls -al |more'		# pipe through 'more'
 169 alias tree='tree -Cs'		# nice alternative to 'ls'
 170 
 171 
 172 # tailoring 'less'
 173 alias more='less'
 174 export PAGER=less
 175 export LESSCHARSET='latin1'
 176 export LESSOPEN='|/usr/bin/lesspipe.sh %s 2>&-' # Use this if lesspipe.sh exists
 177 export LESS='-i -N -w  -z-4 -g -e -M -X -F -R -P%t?f%f \
 178 :stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...'
 179 
 180 # spelling typos - highly personnal :-)
 181 alias xs='cd'
 182 alias vf='cd'
 183 alias moer='more'
 184 alias moew='more'
 185 alias kk='ll'
 186 
 187 #----------------
 188 # a few fun ones
 189 #----------------
 190 
 191 function xtitle ()
 192 {
 193     case $TERM in
 194         *term | rxvt)
 195             echo -n -e "\033]0;$*\007" ;;
 196         *)  ;;
 197     esac
 198 }
 199 
 200 # aliases...
 201 alias top='xtitle Processes on $HOST && top'
 202 alias make='xtitle Making $(basename $PWD) ; make'
 203 alias ncftp="xtitle ncFTP ; ncftp"
 204 
 205 # .. and functions 
 206 function man ()
 207 {
 208     xtitle The $(basename $1|tr -d .[:digit:]) manual
 209     man -a "$*"
 210 }
 211 
 212 function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| egrep -v "^d|total "; }
 213 function xemacs() { { command xemacs -private $* 2>&- & } && disown ;}
 214 function te()  # wrapper around xemacs/gnuserv
 215 {
 216     if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then
 217         gnuclient -q "$@";
 218     else
 219         ( xemacs "$@" & );
 220     fi
 221 }
 222 
 223 #-----------------------------------
 224 # File & strings related functions:
 225 #-----------------------------------
 226 
 227 function ff() { find . -name '*'$1'*' ; }                 # find a file
 228 function fe() { find . -name '*'$1'*' -exec $2 {} \; ; }  # find a file and run $2 on it 
 229 function fstr() # find a string in a set of files
 230 {
 231     if [ "$#" -gt 2 ]; then
 232         echo "Usage: fstr \"pattern\" [files] "
 233         return;
 234     fi
 235     SMSO=$(tput smso)
 236     RMSO=$(tput rmso)
 237     find . -type f -name "${2:-*}" -print | xargs grep -sin "$1" | \
 238 sed "s/$1/$SMSO$1$RMSO/gI"
 239 }
 240 
 241 function cuttail() # cut last n lines in file, 10 by default
 242 {
 243     nlines=${2:-10}
 244     sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
 245 }
 246 
 247 function lowercase()  # move filenames to lowercase
 248 {
 249     for file ; do
 250         filename=${file##*/}
 251         case "$filename" in
 252         */*) dirname==${file%/*} ;;
 253         *) dirname=.;;
 254         esac
 255         nf=$(echo $filename | tr A-Z a-z)
 256         newname="${dirname}/${nf}"
 257         if [ "$nf" != "$filename" ]; then
 258             mv "$file" "$newname"
 259             echo "lowercase: $file --> $newname"
 260         else
 261             echo "lowercase: $file not changed."
 262         fi
 263     done
 264 }
 265 
 266 function swap()         # swap 2 filenames around
 267 {
 268     local TMPFILE=tmp.$$
 269     mv $1 $TMPFILE
 270     mv $2 $1
 271     mv $TMPFILE $2
 272 }
 273 
 274 #-----------------------------------
 275 # Process/system related functions:
 276 #-----------------------------------
 277 
 278 function my_ps() { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
 279 function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
 280 
 281 # This function is roughly the same as 'killall' on linux
 282 # but has no equivalent (that I know of) on Solaris
 283 function killps()   # kill by process name
 284 {
 285     local pid pname sig="-TERM"   # default signal
 286     if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then 
 287 	echo "Usage: killps [-SIGNAL] pattern"
 288 	return;
 289     fi
 290     if [ $# = 2 ]; then sig=$1 ; fi
 291     for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} ) ; do
 292 	pname=$(my_ps | awk '$1~var { print $5 }' var=$pid )
 293 	if ask "Kill process $pid <$pname> with signal $sig?"
 294 	    then kill $sig $pid
 295 	fi
 296     done
 297 }
 298 
 299 function my_ip() # get IP adresses
 300 {
 301     MY_IP=$(/sbin/ifconfig ppp0 | awk '/inet/ { print $2 } ' | sed -e s/addr://)
 302     MY_ISP=$(/sbin/ifconfig ppp0 | awk '/P-t-P/ { print $3 } ' | sed -e s/P-t-P://)
 303 }
 304 
 305 function ii()   # get current host related info
 306 {
 307     echo -e "\nYou are logged on ${RED}$HOST"
 308     echo -e "\nAdditionnal information:$NC " ; uname -a
 309     echo -e "\n${RED}Users logged on:$NC " ; w -h
 310     echo -e "\n${RED}Current date :$NC " ; date
 311     echo -e "\n${RED}Machine stats :$NC " ; uptime
 312     echo -e "\n${RED}Memory stats :$NC " ; free
 313     my_ip 2>&- ;
 314     echo -e "\n${RED}Local IP Address :$NC" ; echo ${MY_IP:-"Not connected"}
 315     echo -e "\n${RED}ISP Address :$NC" ; echo ${MY_ISP:-"Not connected"}
 316     echo
 317 }
 318 
 319 
 320 # Misc utilities:
 321 
 322 function repeat()       # repeat n times command
 323 {
 324     local i max
 325     max=$1; shift;
 326     for ((i=1; i <= max ; i++)); do  # --> C-like syntax
 327         eval "$@";
 328     done
 329 }
 330 
 331 
 332 function ask()
 333 {
 334     echo -n "$@" '[y/n] ' ; read ans
 335     case "$ans" in
 336         y*|Y*) return 0 ;;
 337         *) return 1 ;;
 338     esac
 339 }
 340 
 341 #=========================================================================
 342 #
 343 # PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04
 344 # (Most are taken from the bash 2.05 documentation)
 345 # You will in fact need bash-2.05 for some features
 346 #
 347 #=========================================================================
 348 
 349 if [ "${BASH_VERSION%.*}" \< "2.05" ]; then
 350     echo "You will need to upgrade to version 2.05 for programmable completion"
 351     return
 352 fi
 353 
 354 shopt -s extglob        # necessary
 355 set +o nounset		# otherwise some completions will fail
 356 
 357 complete -A hostname   rsh rcp telnet rlogin r ftp ping disk
 358 complete -A command    nohup exec eval trace gdb
 359 complete -A command    command type which
 360 complete -A export     printenv
 361 complete -A variable   export local readonly unset
 362 complete -A enabled    builtin
 363 complete -A alias      alias unalias
 364 complete -A function   function
 365 complete -A user       su mail finger
 366 
 367 complete -A helptopic  help     # currently same as builtins
 368 complete -A shopt      shopt
 369 complete -A stopped -P '%' bg
 370 complete -A job -P '%'     fg jobs disown
 371 
 372 complete -A directory  mkdir rmdir
 373 complete -A directory   -o default cd
 374 
 375 complete -f -d -X '*.gz'  gzip
 376 complete -f -d -X '*.bz2' bzip2
 377 complete -f -o default -X '!*.gz'  gunzip
 378 complete -f -o default -X '!*.bz2' bunzip2
 379 complete -f -o default -X '!*.pl'  perl perl5
 380 complete -f -o default -X '!*.ps'  gs ghostview ps2pdf ps2ascii
 381 complete -f -o default -X '!*.dvi' dvips dvipdf xdvi dviselect dvitype
 382 complete -f -o default -X '!*.pdf' acroread pdf2ps 
 383 complete -f -o default -X '!*.+(pdf|ps)' gv 
 384 complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
 385 complete -f -o default -X '!*.tex' tex latex slitex 
 386 complete -f -o default -X '!*.lyx' lyx 
 387 complete -f -o default -X '!*.+(jpg|gif|xpm|png|bmp)' xv gimp
 388 complete -f -o default -X '!*.mp3' mpg123 
 389 complete -f -o default -X '!*.ogg' ogg123 
 390 
 391 
 392 # This is a 'universal' completion function - it works when commands have
 393 # a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a' 
 394 _universal_func ()
 395 {
 396     case "$2" in
 397 	-*)	;;
 398 	*)	return ;;
 399     esac
 400 
 401     case "$1" in
 402 	\~*)	eval cmd=$1 ;;
 403 	*)	cmd="$1" ;;
 404     esac
 405     COMPREPLY=( $("$cmd" --help | sed  -e '/--/!d' -e 's/.*--\([^ ]*\).*/--\1/'| \
 406 grep ^"$2" |sort -u) )
 407 }
 408 complete  -o default -F _universal_func ldd wget bash id info
 409 
 410 
 411 _make_targets ()
 412 {
 413     local mdef makef gcmd cur prev i
 414 
 415     COMPREPLY=()
 416     cur=${COMP_WORDS[COMP_CWORD]}
 417     prev=${COMP_WORDS[COMP_CWORD-1]}
 418 
 419     # if prev argument is -f, return possible filename completions.
 420     # we could be a little smarter here and return matches against
 421     # `makefile Makefile *.mk', whatever exists
 422     case "$prev" in
 423         -*f)    COMPREPLY=( $(compgen -f $cur ) ); return 0;;
 424     esac
 425 
 426     # if we want an option, return the possible posix options
 427     case "$cur" in
 428         -)      COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;;
 429     esac
 430 
 431     # make reads `makefile' before `Makefile'
 432     if [ -f makefile ]; then
 433         mdef=makefile
 434     elif [ -f Makefile ]; then
 435         mdef=Makefile
 436     else
 437         mdef=*.mk               # local convention
 438     fi
 439 
 440     # before we scan for targets, see if a makefile name was specified
 441     # with -f
 442     for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
 443         if [[ ${COMP_WORDS[i]} == -*f ]]; then
 444             eval makef=${COMP_WORDS[i+1]}       # eval for tilde expansion
 445             break
 446         fi
 447     done
 448 
 449         [ -z "$makef" ] && makef=$mdef
 450 
 451     # if we have a partial word to complete, restrict completions to
 452     # matches of that word
 453     if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi
 454 
 455     # if we don't want to use *.mk, we can take out the cat and use
 456     # test -f $makef and input redirection
 457     COMPREPLY=( $(cat $makef 2>/dev/null | awk 'BEGIN {FS=":"} /^[^.#   ][^=]*:/ {print $1}' | tr -s ' ' '\012' | sort -u | eval $gcmd ) )
 458 }
 459 
 460 complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake
 461 
 462 _configure_func ()
 463 {
 464     case "$2" in
 465         -*)     ;;
 466         *)      return ;;
 467     esac
 468 
 469     case "$1" in
 470         \~*)    eval cmd=$1 ;;
 471         *)      cmd="$1" ;;
 472     esac
 473 
 474     COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) )
 475 }
 476 
 477 complete -F _configure_func configure
 478 
 479 # cvs(1) completion
 480 _cvs ()
 481 {
 482     local cur prev
 483     COMPREPLY=()
 484     cur=${COMP_WORDS[COMP_CWORD]}
 485     prev=${COMP_WORDS[COMP_CWORD-1]}
 486 
 487     if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
 488 	COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
 489 	export history import log rdiff release remove rtag status \
 490 	tag update' $cur ))
 491     else
 492 	COMPREPLY=( $( compgen -f $cur ))
 493     fi
 494     return 0
 495 }
 496 complete -F _cvs cvs
 497 
 498 
 499 _killall ()
 500 {
 501     local cur prev
 502     COMPREPLY=()
 503     cur=${COMP_WORDS[COMP_CWORD]}
 504 
 505     # get a list of processes (the first sed evaluation
 506     # takes care of swapped out processes, the second
 507     # takes care of getting the basename of the process)
 508     COMPREPLY=( $( /usr/bin/ps -u $USER -o comm  | \
 509         sed -e '1,1d' -e 's#[]\[]##g' -e 's#^.*/##'| \
 510         awk '{if ($0 ~ /^'$cur'/) print $0}' ))
 511 
 512     return 0
 513 }
 514 
 515 complete -F _killall killall killps
 516 
 517 # Local Variables:
 518 # mode:shell-script
 519 # sh-shell:bash
 520 # End: