Appendix M. Sample .bashrc and .bash_profile Files

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 M-1. Sample .bashrc file

   1 # =============================================================== #
   2 #
   3 # PERSONAL $HOME/.bashrc FILE for bash-3.0 (or later)
   4 # By Emmanuel Rouat [no-email]
   5 #
   6 # Last modified: Tue Nov 20 22:04:47 CET 2012
   7 
   8 #  This file is normally read by interactive shells only.
   9 #+ Here is the place to define your aliases, functions and
  10 #+ other interactive features like your prompt.
  11 #
  12 #  The majority of the code here assumes you are on a GNU
  13 #+ system (most likely a Linux box) and is often based on code
  14 #+ found on Usenet or Internet.
  15 #
  16 #  See for instance:
  17 #  http://tldp.org/LDP/abs/html/index.html
  18 #  http://www.caliban.org/bash
  19 #  http://www.shelldorado.com/scripts/categories.html
  20 #  http://www.dotfiles.org
  21 #
  22 #  The choice of colors was done for a shell with a dark background
  23 #+ (white on black), and this is usually also suited for pure text-mode
  24 #+ consoles (no X server available). If you use a white background,
  25 #+ you'll have to do some other choices for readability.
  26 #
  27 #  This bashrc file is a bit overcrowded.
  28 #  Remember, it is just just an example.
  29 #  Tailor it to your needs.
  30 #
  31 # =============================================================== #
  32 
  33 # --> Comments added by HOWTO author.
  34 
  35 # If not running interactively, don't do anything
  36 [ -z "$PS1" ] && return
  37 
  38 
  39 #-------------------------------------------------------------
  40 # Source global definitions (if any)
  41 #-------------------------------------------------------------
  42 
  43 
  44 if [ -f /etc/bashrc ]; then
  45       . /etc/bashrc   # --> Read /etc/bashrc, if present.
  46 fi
  47 
  48 
  49 #--------------------------------------------------------------
  50 #  Automatic setting of $DISPLAY (if not set already).
  51 #  This works for me - your mileage may vary. . . .
  52 #  The problem is that different types of terminals give
  53 #+ different answers to 'who am i' (rxvt in particular can be
  54 #+ troublesome) - however this code seems to work in a majority
  55 #+ of cases.
  56 #--------------------------------------------------------------
  57 
  58 function get_xserver ()
  59 {
  60     case $TERM in
  61         xterm )
  62             XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' )
  63             # Ane-Pieter Wieringa suggests the following alternative:
  64             #  I_AM=$(who am i)
  65             #  SERVER=${I_AM#*(}
  66             #  SERVER=${SERVER%*)}
  67             XSERVER=${XSERVER%%:*}
  68             ;;
  69             aterm | rxvt)
  70             # Find some code that works here. ...
  71             ;;
  72     esac
  73 }
  74 
  75 if [ -z ${DISPLAY:=""} ]; then
  76     get_xserver
  77     if [[ -z ${XSERVER}  || ${XSERVER} == $(hostname) ||
  78        ${XSERVER} == "unix" ]]; then
  79           DISPLAY=":0.0"          # Display on local host.
  80     else
  81        DISPLAY=${XSERVER}:0.0     # Display on remote host.
  82     fi
  83 fi
  84 
  85 export DISPLAY
  86 
  87 #-------------------------------------------------------------
  88 # Some settings
  89 #-------------------------------------------------------------
  90 
  91 #set -o nounset     # These  two options are useful for debugging.
  92 #set -o xtrace
  93 alias debug="set -o nounset; set -o xtrace"
  94 
  95 ulimit -S -c 0      # Don't want coredumps.
  96 set -o notify
  97 set -o noclobber
  98 set -o ignoreeof
  99 
 100 
 101 # Enable options:
 102 shopt -s cdspell
 103 shopt -s cdable_vars
 104 shopt -s checkhash
 105 shopt -s checkwinsize
 106 shopt -s sourcepath
 107 shopt -s no_empty_cmd_completion
 108 shopt -s cmdhist
 109 shopt -s histappend histreedit histverify
 110 shopt -s extglob       # Necessary for programmable completion.
 111 
 112 # Disable options:
 113 shopt -u mailwarn
 114 unset MAILCHECK        # Don't want my shell to warn me of incoming mail.
 115 
 116 
 117 #-------------------------------------------------------------
 118 # Greeting, motd etc. ...
 119 #-------------------------------------------------------------
 120 
 121 # Color definitions (taken from Color Bash Prompt HowTo).
 122 # Some colors might look different of some terminals.
 123 # For example, I see 'Bold Red' as 'orange' on my screen,
 124 # hence the 'Green' 'BRed' 'Red' sequence I often use in my prompt.
 125 
 126 
 127 # Normal Colors
 128 Black='\e[0;30m'        # Black
 129 Red='\e[0;31m'          # Red
 130 Green='\e[0;32m'        # Green
 131 Yellow='\e[0;33m'       # Yellow
 132 Blue='\e[0;34m'         # Blue
 133 Purple='\e[0;35m'       # Purple
 134 Cyan='\e[0;36m'         # Cyan
 135 White='\e[0;37m'        # White
 136 
 137 # Bold
 138 BBlack='\e[1;30m'       # Black
 139 BRed='\e[1;31m'         # Red
 140 BGreen='\e[1;32m'       # Green
 141 BYellow='\e[1;33m'      # Yellow
 142 BBlue='\e[1;34m'        # Blue
 143 BPurple='\e[1;35m'      # Purple
 144 BCyan='\e[1;36m'        # Cyan
 145 BWhite='\e[1;37m'       # White
 146 
 147 # Background
 148 On_Black='\e[40m'       # Black
 149 On_Red='\e[41m'         # Red
 150 On_Green='\e[42m'       # Green
 151 On_Yellow='\e[43m'      # Yellow
 152 On_Blue='\e[44m'        # Blue
 153 On_Purple='\e[45m'      # Purple
 154 On_Cyan='\e[46m'        # Cyan
 155 On_White='\e[47m'       # White
 156 
 157 NC="\e[m"               # Color Reset
 158 
 159 
 160 ALERT=${BWhite}${On_Red} # Bold White on red background
 161 
 162 
 163 
 164 echo -e "${BCyan}This is BASH ${BRed}${BASH_VERSION%.*}${BCyan}\
 165 - DISPLAY on ${BRed}$DISPLAY${NC}\n"
 166 date
 167 if [ -x /usr/games/fortune ]; then
 168     /usr/games/fortune -s     # Makes our day a bit more fun.... :-)
 169 fi
 170 
 171 function _exit()              # Function to run upon exit of shell.
 172 {
 173     echo -e "${BRed}Hasta la vista, baby${NC}"
 174 }
 175 trap _exit EXIT
 176 
 177 #-------------------------------------------------------------
 178 # Shell Prompt - for many examples, see:
 179 #       http://www.debian-administration.org/articles/205
 180 #       http://www.askapache.com/linux/bash-power-prompt.html
 181 #       http://tldp.org/HOWTO/Bash-Prompt-HOWTO
 182 #       https://github.com/nojhan/liquidprompt
 183 #-------------------------------------------------------------
 184 # Current Format: [TIME USER@HOST PWD] >
 185 # TIME:
 186 #    Green     == machine load is low
 187 #    Orange    == machine load is medium
 188 #    Red       == machine load is high
 189 #    ALERT     == machine load is very high
 190 # USER:
 191 #    Cyan      == normal user
 192 #    Orange    == SU to user
 193 #    Red       == root
 194 # HOST:
 195 #    Cyan      == local session
 196 #    Green     == secured remote connection (via ssh)
 197 #    Red       == unsecured remote connection
 198 # PWD:
 199 #    Green     == more than 10% free disk space
 200 #    Orange    == less than 10% free disk space
 201 #    ALERT     == less than 5% free disk space
 202 #    Red       == current user does not have write privileges
 203 #    Cyan      == current filesystem is size zero (like /proc)
 204 # >:
 205 #    White     == no background or suspended jobs in this shell
 206 #    Cyan      == at least one background job in this shell
 207 #    Orange    == at least one suspended job in this shell
 208 #
 209 #    Command is added to the history file each time you hit enter,
 210 #    so it's available to all shells (using 'history -a').
 211 
 212 
 213 # Test connection type:
 214 if [ -n "${SSH_CONNECTION}" ]; then
 215     CNX=${Green}        # Connected on remote machine, via ssh (good).
 216 elif [[ "${DISPLAY%%:0*}" != "" ]]; then
 217     CNX=${ALERT}        # Connected on remote machine, not via ssh (bad).
 218 else
 219     CNX=${BCyan}        # Connected on local machine.
 220 fi
 221 
 222 # Test user type:
 223 if [[ ${USER} == "root" ]]; then
 224     SU=${Red}           # User is root.
 225 elif [[ ${USER} != $(logname) ]]; then
 226     SU=${BRed}          # User is not login user.
 227 else
 228     SU=${BCyan}         # User is normal (well ... most of us are).
 229 fi
 230 
 231 
 232 
 233 NCPU=$(grep -c 'processor' /proc/cpuinfo)    # Number of CPUs
 234 SLOAD=$(( 100*${NCPU} ))        # Small load
 235 MLOAD=$(( 200*${NCPU} ))        # Medium load
 236 XLOAD=$(( 400*${NCPU} ))        # Xlarge load
 237 
 238 # Returns system load as percentage, i.e., '40' rather than '0.40)'.
 239 function load()
 240 {
 241     local SYSLOAD=$(cut -d " " -f1 /proc/loadavg | tr -d '.')
 242     # System load of the current host.
 243     echo $((10#$SYSLOAD))       # Convert to decimal.
 244 }
 245 
 246 # Returns a color indicating system load.
 247 function load_color()
 248 {
 249     local SYSLOAD=$(load)
 250     if [ ${SYSLOAD} -gt ${XLOAD} ]; then
 251         echo -en ${ALERT}
 252     elif [ ${SYSLOAD} -gt ${MLOAD} ]; then
 253         echo -en ${Red}
 254     elif [ ${SYSLOAD} -gt ${SLOAD} ]; then
 255         echo -en ${BRed}
 256     else
 257         echo -en ${Green}
 258     fi
 259 }
 260 
 261 # Returns a color according to free disk space in $PWD.
 262 function disk_color()
 263 {
 264     if [ ! -w "${PWD}" ] ; then
 265         echo -en ${Red}
 266         # No 'write' privilege in the current directory.
 267     elif [ -s "${PWD}" ] ; then
 268         local used=$(command df -P "$PWD" |
 269                    awk 'END {print $5} {sub(/%/,"")}')
 270         if [ ${used} -gt 95 ]; then
 271             echo -en ${ALERT}           # Disk almost full (>95%).
 272         elif [ ${used} -gt 90 ]; then
 273             echo -en ${BRed}            # Free disk space almost gone.
 274         else
 275             echo -en ${Green}           # Free disk space is ok.
 276         fi
 277     else
 278         echo -en ${Cyan}
 279         # Current directory is size '0' (like /proc, /sys etc).
 280     fi
 281 }
 282 
 283 # Returns a color according to running/suspended jobs.
 284 function job_color()
 285 {
 286     if [ $(jobs -s | wc -l) -gt "0" ]; then
 287         echo -en ${BRed}
 288     elif [ $(jobs -r | wc -l) -gt "0" ] ; then
 289         echo -en ${BCyan}
 290     fi
 291 }
 292 
 293 # Adds some text in the terminal frame (if applicable).
 294 
 295 
 296 # Now we construct the prompt.
 297 PROMPT_COMMAND="history -a"
 298 case ${TERM} in
 299   *term | rxvt | linux)
 300         PS1="\[\$(load_color)\][\A\[${NC}\] "
 301         # Time of day (with load info):
 302         PS1="\[\$(load_color)\][\A\[${NC}\] "
 303         # User@Host (with connection type info):
 304         PS1=${PS1}"\[${SU}\]\u\[${NC}\]@\[${CNX}\]\h\[${NC}\] "
 305         # PWD (with 'disk space' info):
 306         PS1=${PS1}"\[\$(disk_color)\]\W]\[${NC}\] "
 307         # Prompt (with 'job' info):
 308         PS1=${PS1}"\[\$(job_color)\]>\[${NC}\] "
 309         # Set title of current xterm:
 310         PS1=${PS1}"\[\e]0;[\u@\h] \w\a\]"
 311         ;;
 312     *)
 313         PS1="(\A \u@\h \W) > " # --> PS1="(\A \u@\h \w) > "
 314                                # --> Shows full pathname of current dir.
 315         ;;
 316 esac
 317 
 318 
 319 
 320 export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
 321 export HISTIGNORE="&:bg:fg:ll:h"
 322 export HISTTIMEFORMAT="$(echo -e ${BCyan})[%d/%m %H:%M:%S]$(echo -e ${NC}) "
 323 export HISTCONTROL=ignoredups
 324 export HOSTFILE=$HOME/.hosts    # Put a list of remote hosts in ~/.hosts
 325 
 326 
 327 #============================================================
 328 #
 329 #  ALIASES AND FUNCTIONS
 330 #
 331 #  Arguably, some functions defined here are quite big.
 332 #  If you want to make this file smaller, these functions can
 333 #+ be converted into scripts and removed from here.
 334 #
 335 #============================================================
 336 
 337 #-------------------
 338 # Personnal Aliases
 339 #-------------------
 340 
 341 alias rm='rm -i'
 342 alias cp='cp -i'
 343 alias mv='mv -i'
 344 # -> Prevents accidentally clobbering files.
 345 alias mkdir='mkdir -p'
 346 
 347 alias h='history'
 348 alias j='jobs -l'
 349 alias which='type -a'
 350 alias ..='cd ..'
 351 
 352 # Pretty-print of some PATH variables:
 353 alias path='echo -e ${PATH//:/\\n}'
 354 alias libpath='echo -e ${LD_LIBRARY_PATH//:/\\n}'
 355 
 356 
 357 alias du='du -kh'    # Makes a more readable output.
 358 alias df='df -kTh'
 359 
 360 #-------------------------------------------------------------
 361 # The 'ls' family (this assumes you use a recent GNU ls).
 362 #-------------------------------------------------------------
 363 # Add colors for filetype and  human-readable sizes by default on 'ls':
 364 alias ls='ls -h --color'
 365 alias lx='ls -lXB'         #  Sort by extension.
 366 alias lk='ls -lSr'         #  Sort by size, biggest last.
 367 alias lt='ls -ltr'         #  Sort by date, most recent last.
 368 alias lc='ls -ltcr'        #  Sort by/show change time,most recent last.
 369 alias lu='ls -ltur'        #  Sort by/show access time,most recent last.
 370 
 371 # The ubiquitous 'll': directories first, with alphanumeric sorting:
 372 alias ll="ls -lv --group-directories-first"
 373 alias lm='ll |more'        #  Pipe through 'more'
 374 alias lr='ll -R'           #  Recursive ls.
 375 alias la='ll -A'           #  Show hidden files.
 376 alias tree='tree -Csuh'    #  Nice alternative to 'recursive ls' ...
 377 
 378 
 379 #-------------------------------------------------------------
 380 # Tailoring 'less'
 381 #-------------------------------------------------------------
 382 
 383 alias more='less'
 384 export PAGER=less
 385 export LESSCHARSET='latin1'
 386 export LESSOPEN='|/usr/bin/lesspipe.sh %s 2>&-'
 387                 # Use this if lesspipe.sh exists.
 388 export LESS='-i -N -w  -z-4 -g -e -M -X -F -R -P%t?f%f \
 389 :stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...'
 390 
 391 # LESS man page colors (makes Man pages more readable).
 392 export LESS_TERMCAP_mb=$'\E[01;31m'
 393 export LESS_TERMCAP_md=$'\E[01;31m'
 394 export LESS_TERMCAP_me=$'\E[0m'
 395 export LESS_TERMCAP_se=$'\E[0m'
 396 export LESS_TERMCAP_so=$'\E[01;44;33m'
 397 export LESS_TERMCAP_ue=$'\E[0m'
 398 export LESS_TERMCAP_us=$'\E[01;32m'
 399 
 400 
 401 #-------------------------------------------------------------
 402 # Spelling typos - highly personnal and keyboard-dependent :-)
 403 #-------------------------------------------------------------
 404 
 405 alias xs='cd'
 406 alias vf='cd'
 407 alias moer='more'
 408 alias moew='more'
 409 alias kk='ll'
 410 
 411 
 412 #-------------------------------------------------------------
 413 # A few fun ones
 414 #-------------------------------------------------------------
 415 
 416 # Adds some text in the terminal frame (if applicable).
 417 
 418 function xtitle()
 419 {
 420     case "$TERM" in
 421     *term* | rxvt)
 422         echo -en  "\e]0;$*\a" ;;
 423     *)  ;;
 424     esac
 425 }
 426 
 427 
 428 # Aliases that use xtitle
 429 alias top='xtitle Processes on $HOST && top'
 430 alias make='xtitle Making $(basename $PWD) ; make'
 431 
 432 # .. and functions
 433 function man()
 434 {
 435     for i ; do
 436         xtitle The $(basename $1|tr -d .[:digit:]) manual
 437         command man -a "$i"
 438     done
 439 }
 440 
 441 
 442 #-------------------------------------------------------------
 443 # Make the following commands run in background automatically:
 444 #-------------------------------------------------------------
 445 
 446 function te()  # wrapper around xemacs/gnuserv
 447 {
 448     if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then
 449        gnuclient -q "$@";
 450     else
 451        ( xemacs "$@" &);
 452     fi
 453 }
 454 
 455 function soffice() { command soffice "$@" & }
 456 function firefox() { command firefox "$@" & }
 457 function xpdf() { command xpdf "$@" & }
 458 
 459 
 460 #-------------------------------------------------------------
 461 # File & strings related functions:
 462 #-------------------------------------------------------------
 463 
 464 
 465 # Find a file with a pattern in name:
 466 function ff() { find . -type f -iname '*'"$*"'*' -ls ; }
 467 
 468 # Find a file with pattern $1 in name and Execute $2 on it:
 469 function fe() { find . -type f -iname '*'"${1:-}"'*' \
 470 -exec ${2:-file} {} \;  ; }
 471 
 472 #  Find a pattern in a set of files and highlight them:
 473 #+ (needs a recent version of egrep).
 474 function fstr()
 475 {
 476     OPTIND=1
 477     local mycase=""
 478     local usage="fstr: find string in files.
 479 Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
 480     while getopts :it opt
 481     do
 482         case "$opt" in
 483            i) mycase="-i " ;;
 484            *) echo "$usage"; return ;;
 485         esac
 486     done
 487     shift $(( $OPTIND - 1 ))
 488     if [ "$#" -lt 1 ]; then
 489         echo "$usage"
 490         return;
 491     fi
 492     find . -type f -name "${2:-*}" -print0 | \
 493 xargs -0 egrep --color=always -sn ${case} "$1" 2>&- | more
 494 
 495 }
 496 
 497 
 498 function swap()
 499 { # Swap 2 filenames around, if they exist (from Uzi's bashrc).
 500     local TMPFILE=tmp.$$
 501 
 502     [ $# -ne 2 ] && echo "swap: 2 arguments needed" && return 1
 503     [ ! -e $1 ] && echo "swap: $1 does not exist" && return 1
 504     [ ! -e $2 ] && echo "swap: $2 does not exist" && return 1
 505 
 506     mv "$1" $TMPFILE
 507     mv "$2" "$1"
 508     mv $TMPFILE "$2"
 509 }
 510 
 511 function extract()      # Handy Extract Program
 512 {
 513     if [ -f $1 ] ; then
 514         case $1 in
 515             *.tar.bz2)   tar xvjf $1     ;;
 516             *.tar.gz)    tar xvzf $1     ;;
 517             *.bz2)       bunzip2 $1      ;;
 518             *.rar)       unrar x $1      ;;
 519             *.gz)        gunzip $1       ;;
 520             *.tar)       tar xvf $1      ;;
 521             *.tbz2)      tar xvjf $1     ;;
 522             *.tgz)       tar xvzf $1     ;;
 523             *.zip)       unzip $1        ;;
 524             *.Z)         uncompress $1   ;;
 525             *.7z)        7z x $1         ;;
 526             *)           echo "'$1' cannot be extracted via >extract<" ;;
 527         esac
 528     else
 529         echo "'$1' is not a valid file!"
 530     fi
 531 }
 532 
 533 
 534 # Creates an archive (*.tar.gz) from given directory.
 535 function maketar() { tar cvzf "${1%%/}.tar.gz"  "${1%%/}/"; }
 536 
 537 # Create a ZIP archive of a file or folder.
 538 function makezip() { zip -r "${1%%/}.zip" "$1" ; }
 539 
 540 # Make your directories and files access rights sane.
 541 function sanitize() { chmod -R u=rwX,g=rX,o= "$@" ;}
 542 
 543 #-------------------------------------------------------------
 544 # Process/system related functions:
 545 #-------------------------------------------------------------
 546 
 547 
 548 function my_ps() { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
 549 function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
 550 
 551 
 552 function killps()   # kill by process name
 553 {
 554     local pid pname sig="-TERM"   # default signal
 555     if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
 556         echo "Usage: killps [-SIGNAL] pattern"
 557         return;
 558     fi
 559     if [ $# = 2 ]; then sig=$1 ; fi
 560     for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} )
 561     do
 562         pname=$(my_ps | awk '$1~var { print $5 }' var=$pid )
 563         if ask "Kill process $pid <$pname> with signal $sig?"
 564             then kill $sig $pid
 565         fi
 566     done
 567 }
 568 
 569 function mydf()         # Pretty-print of 'df' output.
 570 {                       # Inspired by 'dfc' utility.
 571     for fs ; do
 572 
 573         if [ ! -d $fs ]
 574         then
 575           echo -e $fs" :No such file or directory" ; continue
 576         fi
 577 
 578         local info=( $(command df -P $fs | awk 'END{ print $2,$3,$5 }') )
 579         local free=( $(command df -Pkh $fs | awk 'END{ print $4 }') )
 580         local nbstars=$(( 20 * ${info[1]} / ${info[0]} ))
 581         local out="["
 582         for ((j=0;j<20;j++)); do
 583             if [ ${j} -lt ${nbstars} ]; then
 584                out=$out"*"
 585             else
 586                out=$out"-"
 587             fi
 588         done
 589         out=${info[2]}" "$out"] ("$free" free on "$fs")"
 590         echo -e $out
 591     done
 592 }
 593 
 594 
 595 function my_ip() # Get IP adress on ethernet.
 596 {
 597     MY_IP=$(/sbin/ifconfig eth0 | awk '/inet/ { print $2 } ' |
 598       sed -e s/addr://)
 599     echo ${MY_IP:-"Not connected"}
 600 }
 601 
 602 function ii()   # Get current host related info.
 603 {
 604     echo -e "\nYou are logged on ${BRed}$HOST"
 605     echo -e "\n${BRed}Additionnal information:$NC " ; uname -a
 606     echo -e "\n${BRed}Users logged on:$NC " ; w -hs |
 607              cut -d " " -f1 | sort | uniq
 608     echo -e "\n${BRed}Current date :$NC " ; date
 609     echo -e "\n${BRed}Machine stats :$NC " ; uptime
 610     echo -e "\n${BRed}Memory stats :$NC " ; free
 611     echo -e "\n${BRed}Diskspace :$NC " ; mydf / $HOME
 612     echo -e "\n${BRed}Local IP Address :$NC" ; my_ip
 613     echo -e "\n${BRed}Open connections :$NC "; netstat -pan --inet;
 614     echo
 615 }
 616 
 617 #-------------------------------------------------------------
 618 # Misc utilities:
 619 #-------------------------------------------------------------
 620 
 621 function repeat()       # Repeat n times command.
 622 {
 623     local i max
 624     max=$1; shift;
 625     for ((i=1; i <= max ; i++)); do  # --> C-like syntax
 626         eval "$@";
 627     done
 628 }
 629 
 630 
 631 function ask()          # See 'killps' for example of use.
 632 {
 633     echo -n "$@" '[y/n] ' ; read ans
 634     case "$ans" in
 635         y*|Y*) return 0 ;;
 636         *) return 1 ;;
 637     esac
 638 }
 639 
 640 function corename()   # Get name of app that created a corefile.
 641 {
 642     for file ; do
 643         echo -n $file : ; gdb --core=$file --batch | head -1
 644     done
 645 }
 646 
 647 
 648 
 649 #=========================================================================
 650 #
 651 #  PROGRAMMABLE COMPLETION SECTION
 652 #  Most are taken from the bash 2.05 documentation and from Ian McDonald's
 653 # 'Bash completion' package (http://www.caliban.org/bash/#completion)
 654 #  You will in fact need bash more recent then 3.0 for some features.
 655 #
 656 #  Note that most linux distributions now provide many completions
 657 # 'out of the box' - however, you might need to make your own one day,
 658 #  so I kept those here as examples.
 659 #=========================================================================
 660 
 661 if [ "${BASH_VERSION%.*}" \< "3.0" ]; then
 662     echo "You will need to upgrade to version 3.0 for full \
 663           programmable completion features"
 664     return
 665 fi
 666 
 667 shopt -s extglob        # Necessary.
 668 
 669 complete -A hostname   rsh rcp telnet rlogin ftp ping disk
 670 complete -A export     printenv
 671 complete -A variable   export local readonly unset
 672 complete -A enabled    builtin
 673 complete -A alias      alias unalias
 674 complete -A function   function
 675 complete -A user       su mail finger
 676 
 677 complete -A helptopic  help     # Currently same as builtins.
 678 complete -A shopt      shopt
 679 complete -A stopped -P '%' bg
 680 complete -A job -P '%'     fg jobs disown
 681 
 682 complete -A directory  mkdir rmdir
 683 complete -A directory   -o default cd
 684 
 685 # Compression
 686 complete -f -o default -X '*.+(zip|ZIP)'  zip
 687 complete -f -o default -X '!*.+(zip|ZIP)' unzip
 688 complete -f -o default -X '*.+(z|Z)'      compress
 689 complete -f -o default -X '!*.+(z|Z)'     uncompress
 690 complete -f -o default -X '*.+(gz|GZ)'    gzip
 691 complete -f -o default -X '!*.+(gz|GZ)'   gunzip
 692 complete -f -o default -X '*.+(bz2|BZ2)'  bzip2
 693 complete -f -o default -X '!*.+(bz2|BZ2)' bunzip2
 694 complete -f -o default -X '!*.+(zip|ZIP|z|Z|gz|GZ|bz2|BZ2)' extract
 695 
 696 
 697 # Documents - Postscript,pdf,dvi.....
 698 complete -f -o default -X '!*.+(ps|PS)'  gs ghostview ps2pdf ps2ascii
 699 complete -f -o default -X \
 700 '!*.+(dvi|DVI)' dvips dvipdf xdvi dviselect dvitype
 701 complete -f -o default -X '!*.+(pdf|PDF)' acroread pdf2ps
 702 complete -f -o default -X '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?\
 703 (.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv
 704 complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
 705 complete -f -o default -X '!*.tex' tex latex slitex
 706 complete -f -o default -X '!*.lyx' lyx
 707 complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps
 708 complete -f -o default -X \
 709 '!*.+(doc|DOC|xls|XLS|ppt|PPT|sx?|SX?|csv|CSV|od?|OD?|ott|OTT)' soffice
 710 
 711 # Multimedia
 712 complete -f -o default -X \
 713 '!*.+(gif|GIF|jp*g|JP*G|bmp|BMP|xpm|XPM|png|PNG)' xv gimp ee gqview
 714 complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321
 715 complete -f -o default -X '!*.+(ogg|OGG)' ogg123
 716 complete -f -o default -X \
 717 '!*.@(mp[23]|MP[23]|ogg|OGG|wav|WAV|pls|\
 718 m3u|xm|mod|s[3t]m|it|mtm|ult|flac)' xmms
 719 complete -f -o default -X '!*.@(mp?(e)g|MP?(E)G|wma|avi|AVI|\
 720 asf|vob|VOB|bin|dat|vcd|ps|pes|fli|viv|rm|ram|yuv|mov|MOV|qt|\
 721 QT|wmv|mp3|MP3|ogg|OGG|ogm|OGM|mp4|MP4|wav|WAV|asx|ASX)' xine
 722 
 723 
 724 
 725 complete -f -o default -X '!*.pl'  perl perl5
 726 
 727 
 728 #  This is a 'universal' completion function - it works when commands have
 729 #+ a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a'
 730 #  Needs the '-o' option of grep
 731 #+ (try the commented-out version if not available).
 732 
 733 #  First, remove '=' from completion word separators
 734 #+ (this will allow completions like 'ls --color=auto' to work correctly).
 735 
 736 COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
 737 
 738 
 739 _get_longopts()
 740 {
 741   #$1 --help | sed  -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
 742   #grep ^"$2" |sort -u ;
 743     $1 --help | grep -o -e "--[^[:space:].,]*" | grep -e "$2" |sort -u
 744 }
 745 
 746 _longopts()
 747 {
 748     local cur
 749     cur=${COMP_WORDS[COMP_CWORD]}
 750 
 751     case "${cur:-*}" in
 752        -*)      ;;
 753         *)      return ;;
 754     esac
 755 
 756     case "$1" in
 757        \~*)     eval cmd="$1" ;;
 758          *)     cmd="$1" ;;
 759     esac
 760     COMPREPLY=( $(_get_longopts ${1} ${cur} ) )
 761 }
 762 complete  -o default -F _longopts configure bash
 763 complete  -o default -F _longopts wget id info a2ps ls recode
 764 
 765 _tar()
 766 {
 767     local cur ext regex tar untar
 768 
 769     COMPREPLY=()
 770     cur=${COMP_WORDS[COMP_CWORD]}
 771 
 772     # If we want an option, return the possible long options.
 773     case "$cur" in
 774         -*)     COMPREPLY=( $(_get_longopts $1 $cur ) ); return 0;;
 775     esac
 776 
 777     if [ $COMP_CWORD -eq 1 ]; then
 778         COMPREPLY=( $( compgen -W 'c t x u r d A' -- $cur ) )
 779         return 0
 780     fi
 781 
 782     case "${COMP_WORDS[1]}" in
 783         ?(-)c*f)
 784             COMPREPLY=( $( compgen -f $cur ) )
 785             return 0
 786             ;;
 787         +([^Izjy])f)
 788             ext='tar'
 789             regex=$ext
 790             ;;
 791         *z*f)
 792             ext='tar.gz'
 793             regex='t\(ar\.\)\(gz\|Z\)'
 794             ;;
 795         *[Ijy]*f)
 796             ext='t?(ar.)bz?(2)'
 797             regex='t\(ar\.\)bz2\?'
 798             ;;
 799         *)
 800             COMPREPLY=( $( compgen -f $cur ) )
 801             return 0
 802             ;;
 803 
 804     esac
 805 
 806     if [[ "$COMP_LINE" == tar*.$ext' '* ]]; then
 807         # Complete on files in tar file.
 808         #
 809         # Get name of tar file from command line.
 810         tar=$( echo "$COMP_LINE" | \
 811                         sed -e 's|^.* \([^ ]*'$regex'\) .*$|\1|' )
 812         # Devise how to untar and list it.
 813         untar=t${COMP_WORDS[1]//[^Izjyf]/}
 814 
 815         COMPREPLY=( $( compgen -W "$( echo $( tar $untar $tar \
 816                                 2>/dev/null ) )" -- "$cur" ) )
 817         return 0
 818 
 819     else
 820         # File completion on relevant files.
 821         COMPREPLY=( $( compgen -G $cur\*.$ext ) )
 822 
 823     fi
 824 
 825     return 0
 826 
 827 }
 828 
 829 complete -F _tar -o default tar
 830 
 831 _make()
 832 {
 833     local mdef makef makef_dir="." makef_inc gcmd cur prev i;
 834     COMPREPLY=();
 835     cur=${COMP_WORDS[COMP_CWORD]};
 836     prev=${COMP_WORDS[COMP_CWORD-1]};
 837     case "$prev" in
 838         -*f)
 839             COMPREPLY=($(compgen -f $cur ));
 840             return 0
 841             ;;
 842     esac;
 843     case "$cur" in
 844         -*)
 845             COMPREPLY=($(_get_longopts $1 $cur ));
 846             return 0
 847             ;;
 848     esac;
 849 
 850     # ... make reads
 851     #          GNUmakefile,
 852     #     then makefile
 853     #     then Makefile ...
 854     if [ -f ${makef_dir}/GNUmakefile ]; then
 855         makef=${makef_dir}/GNUmakefile
 856     elif [ -f ${makef_dir}/makefile ]; then
 857         makef=${makef_dir}/makefile
 858     elif [ -f ${makef_dir}/Makefile ]; then
 859         makef=${makef_dir}/Makefile
 860     else
 861        makef=${makef_dir}/*.mk         # Local convention.
 862     fi
 863 
 864 
 865     #  Before we scan for targets, see if a Makefile name was
 866     #+ specified with -f.
 867     for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
 868         if [[ ${COMP_WORDS[i]} == -f ]]; then
 869             # eval for tilde expansion
 870             eval makef=${COMP_WORDS[i+1]}
 871             break
 872         fi
 873     done
 874     [ ! -f $makef ] && return 0
 875 
 876     # Deal with included Makefiles.
 877     makef_inc=$( grep -E '^-?include' $makef |
 878                  sed -e "s,^.* ,"$makef_dir"/," )
 879     for file in $makef_inc; do
 880         [ -f $file ] && makef="$makef $file"
 881     done
 882 
 883 
 884     #  If we have a partial word to complete, restrict completions
 885     #+ to matches of that word.
 886     if [ -n "$cur" ]; then gcmd='grep "^$cur"' ; else gcmd=cat ; fi
 887 
 888     COMPREPLY=( $( awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \
 889                                {split($1,A,/ /);for(i in A)print A[i]}' \
 890                                 $makef 2>/dev/null | eval $gcmd  ))
 891 
 892 }
 893 
 894 complete -F _make -X '+($*|*.[cho])' make gmake pmake
 895 
 896 
 897 
 898 
 899 _killall()
 900 {
 901     local cur prev
 902     COMPREPLY=()
 903     cur=${COMP_WORDS[COMP_CWORD]}
 904 
 905     #  Get a list of processes
 906     #+ (the first sed evaluation
 907     #+ takes care of swapped out processes, the second
 908     #+ takes care of getting the basename of the process).
 909     COMPREPLY=( $( ps -u $USER -o comm  | \
 910         sed -e '1,1d' -e 's#[]\[]##g' -e 's#^.*/##'| \
 911         awk '{if ($0 ~ /^'$cur'/) print $0}' ))
 912 
 913     return 0
 914 }
 915 
 916 complete -F _killall killall killps
 917 
 918 
 919 
 920 # Local Variables:
 921 # mode:shell-script
 922 # sh-shell:bash
 923 # End:

And, here is a snippet from Andrzej Szelachowski's instructive .bash_profile file.


Example M-2. .bash_profile file

   1 # From Andrzej Szelachowski's ~/.bash_profile:
   2 
   3 
   4 #  Note that a variable may require special treatment
   5 #+ if it will be exported.
   6 
   7 DARKGRAY='\e[1;30m'
   8 LIGHTRED='\e[1;31m'
   9 GREEN='\e[32m'
  10 YELLOW='\e[1;33m'
  11 LIGHTBLUE='\e[1;34m'
  12 NC='\e[m'
  13 
  14 PCT="\`if [[ \$EUID -eq 0 ]]; then T='$LIGHTRED' ; else T='$LIGHTBLUE'; fi; 
  15 echo \$T \`"
  16 
  17 #  For "literal" command substitution to be assigned to a variable,
  18 #+ use escapes and double quotes:
  19 #+       PCT="\` ... \`" . . .
  20 #  Otherwise, the value of PCT variable is assigned only once,
  21 #+ when the variable is exported/read from .bash_profile,
  22 #+ and it will not change afterwards even if the user ID changes.
  23 
  24 
  25 PS1="\n$GREEN[\w] \n$DARKGRAY($PCT\t$DARKGRAY)-($PCT\u$DARKGRAY)-($PCT\!
  26 $DARKGRAY)$YELLOW-> $NC"
  27 
  28 #  Escape a variables whose value changes:
  29 #        if [[ \$EUID -eq 0 ]],
  30 #  Otherwise the value of the EUID variable will be assigned only once,
  31 #+ as above.
  32 
  33 #  When a variable is assigned, it should be called escaped:
  34 #+       echo \$T,
  35 #  Otherwise the value of the T variable is taken from the moment the PCT 
  36 #+ variable is exported/read from .bash_profile.
  37 #  So, in this example it would be null.
  38 
  39 #  When a variable's value contains a semicolon it should be strong quoted:
  40 #        T='$LIGHTRED',
  41 #  Otherwise, the semicolon will be interpreted as a command separator.
  42 
  43 
  44 #  Variables PCT and PS1 can be merged into a new PS1 variable:
  45 
  46 PS1="\`if [[ \$EUID -eq 0 ]]; then PCT='$LIGHTRED';
  47 else PCT='$LIGHTBLUE'; fi; 
  48 echo '\n$GREEN[\w] \n$DARKGRAY('\$PCT'\t$DARKGRAY)-\
  49 ('\$PCT'\u$DARKGRAY)-('\$PCT'\!$DARKGRAY)$YELLOW-> $NC'\`"
  50 
  51 # The trick is to use strong quoting for parts of old PS1 variable.