Appendix K. 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 K-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: Sun Nov 30 16:27:45 CET 2008
   7 # This file is read (normally) by interactive shells only.
   8 # Here is the place to define your aliases, functions and
   9 # other interactive features like your prompt.
  10 #
  11 # The majority of the code here assumes you are on a GNU 
  12 # system (most likely a Linux box) and is based on code found
  13 # on Usenet or internet. See for instance:
  14 #
  15 # http://tldp.org/LDP/abs/html/index.html
  16 # http://www.caliban.org/bash/
  17 # http://www.shelldorado.com/scripts/categories.html
  18 # http://www.dotfiles.org/
  19 #
  20 # This bashrc file is a bit overcrowded -- remember it is just
  21 # just an example. Tailor it to your needs.
  22 #
  23 #
  24 #=============================================================
  25 
  26 # --> Comments added by HOWTO author.
  27 
  28 
  29 #-------------------------------------------------------------
  30 # Source global definitions (if any)
  31 #-------------------------------------------------------------
  32 
  33 
  34 if [ -f /etc/bashrc ]; then
  35         . /etc/bashrc   # --> Read /etc/bashrc, if present.
  36 fi
  37 
  38 #-------------------------------------------------------------
  39 # Automatic setting of $DISPLAY (if not set already).
  40 # This works for linux - your mileage may vary. ... 
  41 # The problem is that different types of terminals give
  42 # different answers to 'who am i' (rxvt in particular can be
  43 # troublesome).
  44 # I have not found a 'universal' method yet.
  45 #-------------------------------------------------------------
  46 
  47 function get_xserver ()
  48 {
  49     case $TERM in
  50        xterm )
  51             XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' ) 
  52             # Ane-Pieter Wieringa suggests the following alternative:
  53             # I_AM=$(who am i)
  54             # SERVER=${I_AM#*(}
  55             # SERVER=${SERVER%*)}
  56 
  57             XSERVER=${XSERVER%%:*}
  58             ;;
  59         aterm | rxvt)
  60         # Find some code that works here. ...
  61             ;;
  62     esac  
  63 }
  64 
  65 if [ -z ${DISPLAY:=""} ]; then
  66     get_xserver
  67     if [[ -z ${XSERVER}  || ${XSERVER} == $(hostname) || \
  68       ${XSERVER} == "unix" ]]; then 
  69         DISPLAY=":0.0"          # Display on local host.
  70     else
  71         DISPLAY=${XSERVER}:0.0  # Display on remote host.
  72     fi
  73 fi
  74 
  75 export DISPLAY
  76 
  77 #-------------------------------------------------------------
  78 # Some settings
  79 #-------------------------------------------------------------
  80 
  81 ulimit -S -c 0          # Don't want any coredumps.
  82 set -o notify
  83 set -o noclobber
  84 set -o ignoreeof
  85 set -o nounset
  86 #set -o xtrace          # Useful for debuging.
  87 
  88 # Enable options:
  89 shopt -s cdspell
  90 shopt -s cdable_vars
  91 shopt -s checkhash
  92 shopt -s checkwinsize
  93 shopt -s sourcepath
  94 shopt -s no_empty_cmd_completion
  95 shopt -s cmdhist
  96 shopt -s histappend histreedit histverify
  97 shopt -s extglob        # Necessary for programmable completion.
  98 
  99 # Disable options:
 100 shopt -u mailwarn
 101 unset MAILCHECK         # Don't want my shell to warn me of incoming mail.
 102 
 103 
 104 export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
 105 export HISTTIMEFORMAT="%H:%M > "
 106 export HISTIGNORE="&:bg:fg:ll:h"
 107 export HOSTFILE=$HOME/.hosts    # Put list of remote hosts in ~/.hosts ...
 108 
 109 
 110 
 111 #-------------------------------------------------------------
 112 # Greeting, motd etc...
 113 #-------------------------------------------------------------
 114 
 115 # Define some colors first:
 116 red='\e[0;31m'
 117 RED='\e[1;31m'
 118 blue='\e[0;34m'
 119 BLUE='\e[1;34m'
 120 cyan='\e[0;36m'
 121 CYAN='\e[1;36m'
 122 NC='\e[0m'              # No Color
 123 # --> Nice. Has the same effect as using "ansi.sys" in DOS.
 124 
 125 
 126 # Looks best on a terminal with black background.....
 127 echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}\
 128 ${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n"
 129 date
 130 if [ -x /usr/games/fortune ]; then
 131     /usr/games/fortune -s     # Makes our day a bit more fun.... :-)
 132 fi
 133 
 134 function _exit()        # Function to run upon exit of shell.
 135 {
 136     echo -e "${RED}Hasta la vista, baby${NC}"
 137 }
 138 trap _exit EXIT
 139 
 140 
 141 #-------------------------------------------------------------
 142 # Shell Prompt
 143 #-------------------------------------------------------------
 144 
 145 
 146 if [[ "${DISPLAY%%:0*}" != "" ]]; then  
 147     HILIT=${red}   # remote machine: prompt will be partly red
 148 else
 149     HILIT=${cyan}  # local machine: prompt will be partly cyan
 150 fi
 151 
 152 #  --> Replace instances of \W with \w in prompt functions below
 153 #+ --> to get display of full path name.
 154 
 155 function fastprompt()
 156 {
 157     unset PROMPT_COMMAND
 158     case $TERM in
 159         *term | rxvt )
 160             PS1="${HILIT}[\h]$NC \W > \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
 161         linux )
 162             PS1="${HILIT}[\h]$NC \W > " ;;
 163         *)
 164             PS1="[\h] \W > " ;;
 165     esac
 166 }
 167 
 168 
 169 _powerprompt()
 170 {
 171     LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
 172 }
 173 
 174 function powerprompt()
 175 {
 176 
 177     PROMPT_COMMAND=_powerprompt
 178     case $TERM in
 179         *term | rxvt  )
 180             PS1="${HILIT}[\A - \$LOAD]$NC\n[\u@\h \#] \W > \
 181                  \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
 182         linux )
 183             PS1="${HILIT}[\A - \$LOAD]$NC\n[\u@\h \#] \W > " ;;
 184         * )
 185             PS1="[\A - \$LOAD]\n[\u@\h \#] \W > " ;;
 186     esac
 187 }
 188 
 189 powerprompt     # This is the default prompt -- might be slow.
 190                 # If too slow, use fastprompt instead. ...
 191 
 192 #===============================================================
 193 #
 194 # ALIASES AND FUNCTIONS
 195 #
 196 # Arguably, some functions defined here are quite big.
 197 # If you want to make this file smaller, these functions can
 198 # be converted into scripts and removed from here.
 199 #
 200 # Many functions were taken (almost) straight from the bash-2.04
 201 # examples.
 202 #
 203 #===============================================================
 204 
 205 #-------------------
 206 # Personnal Aliases
 207 #-------------------
 208 
 209 alias rm='rm -i'
 210 alias cp='cp -i'
 211 alias mv='mv -i'
 212 # -> Prevents accidentally clobbering files.
 213 alias mkdir='mkdir -p'
 214 
 215 alias h='history'
 216 alias j='jobs -l'
 217 alias which='type -a'
 218 alias ..='cd ..'
 219 alias path='echo -e ${PATH//:/\\n}'
 220 alias libpath='echo -e ${LD_LIBRARY_PATH//:/\\n}'
 221 alias print='/usr/bin/lp -o nobanner -d $LPDEST'
 222             # Assumes LPDEST is defined (default printer)
 223 alias pjet='enscript -h -G -fCourier9 -d $LPDEST'
 224             # Pretty-print using enscript
 225 
 226 alias du='du -kh'       # Makes a more readable output.
 227 alias df='df -kTh'
 228 
 229 #-------------------------------------------------------------
 230 # The 'ls' family (this assumes you use a recent GNU ls)
 231 #-------------------------------------------------------------
 232 alias ll="ls -l --group-directories-first"
 233 alias ls='ls -hF --color'  # add colors for filetype recognition
 234 alias la='ls -Al'          # show hidden files
 235 alias lx='ls -lXB'         # sort by extension
 236 alias lk='ls -lSr'         # sort by size, biggest last
 237 alias lc='ls -ltcr'        # sort by and show change time, most recent last
 238 alias lu='ls -ltur'        # sort by and show access time, most recent last
 239 alias lt='ls -ltr'         # sort by date, most recent last
 240 alias lm='ls -al |more'    # pipe through 'more'
 241 alias lr='ls -lR'          # recursive ls
 242 alias tree='tree -Csu'     # nice alternative to 'recursive ls'
 243 
 244 # If your version of 'ls' doesn't support --group-directories-first try this:
 245 # function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| \
 246 #                egrep -v "^d|total "; }
 247 
 248 
 249 #-------------------------------------------------------------
 250 # tailoring 'less'
 251 #-------------------------------------------------------------
 252 
 253 alias more='less'
 254 export PAGER=less
 255 export LESSCHARSET='latin1'
 256 export LESSOPEN='|/usr/bin/lesspipe.sh %s 2>&-'
 257    # Use this if lesspipe.sh exists
 258 export LESS='-i -N -w  -z-4 -g -e -M -X -F -R -P%t?f%f \
 259 :stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...'
 260 
 261 
 262 #-------------------------------------------------------------
 263 # spelling typos - highly personnal and keyboard-dependent :-)
 264 #-------------------------------------------------------------
 265 
 266 alias xs='cd'
 267 alias vf='cd'
 268 alias moer='more'
 269 alias moew='more'
 270 alias kk='ll'
 271 
 272 
 273 #-------------------------------------------------------------
 274 # A few fun ones
 275 #-------------------------------------------------------------
 276 
 277 
 278 function xtitle()      # Adds some text in the terminal frame.
 279 {
 280     case "$TERM" in
 281         *term | rxvt)
 282             echo -n -e "\033]0;$*\007" ;;
 283         *)  
 284             ;;
 285     esac
 286 }
 287 
 288 # aliases that use xtitle
 289 alias top='xtitle Processes on $HOST && top'
 290 alias make='xtitle Making $(basename $PWD) ; make'
 291 alias ncftp="xtitle ncFTP ; ncftp"
 292 
 293 # .. and functions
 294 function man()
 295 {
 296     for i ; do
 297         xtitle The $(basename $1|tr -d .[:digit:]) manual
 298         command man -F -a "$i"
 299     done
 300 }
 301 
 302 
 303 #-------------------------------------------------------------
 304 # Make the following commands run in background automatically:
 305 #-------------------------------------------------------------
 306 
 307 function te()  # Wrapper around xemacs/gnuserv ...
 308 {
 309     if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then
 310         gnuclient -q "$@";
 311     else
 312         ( xemacs "$@" &);
 313     fi
 314 }
 315 
 316 function soffice() { command soffice "$@" & }
 317 function firefox() { command firefox "$@" & }
 318 function xpdf() { command xpdf "$@" & }
 319 
 320 
 321 #-------------------------------------------------------------
 322 # File & string-related functions:
 323 #-------------------------------------------------------------
 324 
 325 
 326 # Find a file with a pattern in name:
 327 function ff() { find . -type f -iname '*'$*'*' -ls ; }
 328 
 329 # Find a file with pattern $1 in name and Execute $2 on it:
 330 function fe()
 331 { find . -type f -iname '*'${1:-}'*' -exec ${2:-file} {} \;  ; }
 332 
 333 # Find a pattern in a set of files and highlight them:
 334 # (needs a recent version of egrep)
 335 function fstr()
 336 {
 337     OPTIND=1
 338     local case=""
 339     local usage="fstr: find string in files.
 340 Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
 341     while getopts :it opt
 342     do
 343         case "$opt" in
 344         i) case="-i " ;;
 345         *) echo "$usage"; return;;
 346         esac
 347     done
 348     shift $(( $OPTIND - 1 ))
 349     if [ "$#" -lt 1 ]; then
 350         echo "$usage"
 351         return;
 352     fi
 353     find . -type f -name "${2:-*}" -print0 | \
 354     xargs -0 egrep --color=always -sn ${case} "$1" 2>&- | more 
 355 
 356 }
 357 
 358 function cuttail() # cut last n lines in file, 10 by default
 359 {
 360     nlines=${2:-10}
 361     sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
 362 }
 363 
 364 function lowercase()  # move filenames to lowercase
 365 {
 366     for file ; do
 367         filename=${file##*/}
 368         case "$filename" in
 369         */*) dirname==${file%/*} ;;
 370         *) dirname=.;;
 371         esac
 372         nf=$(echo $filename | tr A-Z a-z)
 373         newname="${dirname}/${nf}"
 374         if [ "$nf" != "$filename" ]; then
 375             mv "$file" "$newname"
 376             echo "lowercase: $file --> $newname"
 377         else
 378             echo "lowercase: $file not changed."
 379         fi
 380     done
 381 }
 382 
 383 
 384 function swap()  # Swap 2 filenames around, if they exist
 385 {                #(from Uzi's bashrc).
 386     local TMPFILE=tmp.$$ 
 387 
 388     [ $# -ne 2 ] && echo "swap: 2 arguments needed" && return 1
 389     [ ! -e $1 ] && echo "swap: $1 does not exist" && return 1
 390     [ ! -e $2 ] && echo "swap: $2 does not exist" && return 1
 391 
 392     mv "$1" $TMPFILE 
 393     mv "$2" "$1"
 394     mv $TMPFILE "$2"
 395 }
 396 
 397 function extract()      # Handy Extract Program.
 398 {
 399      if [ -f $1 ] ; then
 400          case $1 in
 401              *.tar.bz2)   tar xvjf $1     ;;
 402              *.tar.gz)    tar xvzf $1     ;;
 403              *.bz2)       bunzip2 $1      ;;
 404              *.rar)       unrar x $1      ;;
 405              *.gz)        gunzip $1       ;;
 406              *.tar)       tar xvf $1      ;;
 407              *.tbz2)      tar xvjf $1     ;;
 408              *.tgz)       tar xvzf $1     ;;
 409              *.zip)       unzip $1        ;;
 410              *.Z)         uncompress $1   ;;
 411              *.7z)        7z x $1         ;;
 412              *)           echo "'$1' cannot be extracted via >extract<" ;;
 413          esac
 414      else
 415          echo "'$1' is not a valid file"
 416      fi
 417 }
 418 
 419 #-------------------------------------------------------------
 420 # Process/system related functions:
 421 #-------------------------------------------------------------
 422 
 423 
 424 function my_ps() { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
 425 function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
 426 
 427 
 428 function killps()                 # Kill by process name.
 429 {
 430     local pid pname sig="-TERM"   # Default signal.
 431     if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
 432         echo "Usage: killps [-SIGNAL] pattern"
 433         return;
 434     fi
 435     if [ $# = 2 ]; then sig=$1 ; fi
 436     for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} ) ; do
 437         pname=$(my_ps | awk '$1~var { print $5 }' var=$pid )
 438         if ask "Kill process $pid <$pname> with signal $sig?"
 439             then kill $sig $pid
 440         fi
 441     done
 442 }
 443 
 444 function my_ip() # Get IP adresses.
 445 {
 446     MY_IP=$(/sbin/ifconfig ppp0 | awk '/inet/ { print $2 } ' | \
 447 sed -e s/addr://)
 448     MY_ISP=$(/sbin/ifconfig ppp0 | awk '/P-t-P/ { print $3 } ' | \
 449 sed -e s/P-t-P://)
 450 }
 451 
 452 function ii()   # Get current host related info.
 453 {
 454     echo -e "\nYou are logged on ${RED}$HOST"
 455     echo -e "\nAdditionnal information:$NC " ; uname -a
 456     echo -e "\n${RED}Users logged on:$NC " ; w -h
 457     echo -e "\n${RED}Current date :$NC " ; date
 458     echo -e "\n${RED}Machine stats :$NC " ; uptime
 459     echo -e "\n${RED}Memory stats :$NC " ; free
 460     my_ip 2>&- ;
 461     echo -e "\n${RED}Local IP Address :$NC" ; echo ${MY_IP:-"Not connected"}
 462     echo -e "\n${RED}ISP Address :$NC" ; echo ${MY_ISP:-"Not connected"}
 463     echo -e "\n${RED}Open connections :$NC "; netstat -pan --inet;
 464     echo
 465 }
 466 
 467 #-------------------------------------------------------------
 468 # Misc utilities:
 469 #-------------------------------------------------------------
 470 
 471 function repeat()       # Repeat n times command.
 472 {
 473     local i max
 474     max=$1; shift;
 475     for ((i=1; i <= max ; i++)); do  # --> C-like syntax
 476         eval "$@";
 477     done
 478 }
 479 
 480 
 481 function ask()          # See 'killps' for example of use.
 482 {
 483     echo -n "$@" '[y/n] ' ; read ans
 484     case "$ans" in
 485         y*|Y*) return 0 ;;
 486         *) return 1 ;;
 487     esac
 488 }
 489 
 490 function corename()   # Get name of app that created a corefile.
 491 { 
 492     for file ; do
 493         echo -n $file : ; gdb --core=$file --batch | head -1
 494     done 
 495 }
 496 
 497 
 498 
 499 
 500 #=========================================================================
 501 # PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04
 502 # Most are taken from the bash 2.05 documentation and from Ian McDonald's
 503 # 'Bash completion' package (http://www.caliban.org/bash/#completion).
 504 # You will in fact need bash more recent than 3.0 for some features.
 505 #=========================================================================
 506 
 507 if [ "${BASH_VERSION%.*}" \< "3.0" ]; then
 508     echo "You will need to upgrade to version 3.0 \
 509 for full programmable completion features."
 510     return
 511 fi
 512 
 513 shopt -s extglob         # Necessary,
 514 #set +o nounset          # otherwise some completions will fail.
 515 
 516 complete -A hostname   rsh rcp telnet rlogin r ftp ping disk
 517 complete -A export     printenv
 518 complete -A variable   export local readonly unset
 519 complete -A enabled    builtin
 520 complete -A alias      alias unalias
 521 complete -A function   function
 522 complete -A user       su mail finger
 523 
 524 complete -A helptopic  help     # Currently, same as builtins.
 525 complete -A shopt      shopt
 526 complete -A stopped -P '%' bg
 527 complete -A job -P '%'     fg jobs disown
 528 
 529 complete -A directory  mkdir rmdir
 530 complete -A directory   -o default cd
 531 
 532 # Compression
 533 complete -f -o default -X '*.+(zip|ZIP)'  zip
 534 complete -f -o default -X '!*.+(zip|ZIP)' unzip
 535 complete -f -o default -X '*.+(z|Z)'      compress
 536 complete -f -o default -X '!*.+(z|Z)'     uncompress
 537 complete -f -o default -X '*.+(gz|GZ)'    gzip
 538 complete -f -o default -X '!*.+(gz|GZ)'   gunzip
 539 complete -f -o default -X '*.+(bz2|BZ2)'  bzip2
 540 complete -f -o default -X '!*.+(bz2|BZ2)' bunzip2
 541 complete -f -o default -X '!*.+(zip|ZIP|z|Z|gz|GZ|bz2|BZ2)' extract
 542 
 543 
 544 # Documents - Postscript,pdf,dvi.....
 545 complete -f -o default -X '!*.+(ps|PS)'  gs ghostview ps2pdf ps2ascii
 546 complete -f -o default -X '!*.+(dvi|DVI)' dvips dvipdf xdvi dviselect dvitype
 547 complete -f -o default -X '!*.+(pdf|PDF)' acroread pdf2ps
 548 complete -f -o default -X \
 549 '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv
 550 complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
 551 complete -f -o default -X '!*.tex' tex latex slitex
 552 complete -f -o default -X '!*.lyx' lyx
 553 complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps
 554 complete -f -o default -X \
 555 '!*.+(doc|DOC|xls|XLS|ppt|PPT|sx?|SX?|csv|CSV|od?|OD?|ott|OTT)' soffice
 556 
 557 # Multimedia
 558 complete -f -o default -X \
 559 '!*.+(gif|GIF|jp*g|JP*G|bmp|BMP|xpm|XPM|png|PNG)' xv gimp ee gqview
 560 complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321
 561 complete -f -o default -X '!*.+(ogg|OGG)' ogg123
 562 complete -f -o default -X \
 563 '!*.@(mp[23]|MP[23]|ogg|OGG|wav|WAV|pls|m3u|xm|mod|s[3t]m|it|mtm|ult|flac)' xmms
 564 complete -f -o default -X \
 565 '!*.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|vcd|\
 566 ps|pes|fli|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp3|MP3|ogg|OGG|\
 567 ogm|OGM|mp4|MP4|wav|WAV|asx|ASX)' xine
 568 
 569 
 570 
 571 complete -f -o default -X '!*.pl'  perl perl5
 572 
 573 
 574 # This is a 'universal' completion function - it works when commands have
 575 # a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a'
 576 # Needs the '-o' option of grep
 577 #  (try the commented-out version if not available).
 578 
 579 # First, remove '=' from completion word separators
 580 # (this will allow completions like 'ls --color=auto' to work correctly).
 581 
 582 COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
 583 
 584 
 585 _get_longopts() 
 586 { 
 587     #$1 --help | sed  -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
 588 #grep ^"$2" |sort -u ;
 589     $1 --help | grep -o -e "--[^[:space:].,]*" | grep -e "$2" |sort -u 
 590 }
 591 
 592 _longopts()
 593 {
 594     local cur
 595     cur=${COMP_WORDS[COMP_CWORD]}
 596 
 597     case "${cur:-*}" in
 598        -*)      ;;
 599         *)      return ;;
 600     esac
 601 
 602     case "$1" in
 603       \~*)      eval cmd="$1" ;;
 604         *)      cmd="$1" ;;
 605     esac
 606     COMPREPLY=( $(_get_longopts ${1} ${cur} ) )
 607 }
 608 complete  -o default -F _longopts configure bash
 609 complete  -o default -F _longopts wget id info a2ps ls recode
 610 
 611 _tar()
 612 {
 613     local cur ext regex tar untar
 614 
 615     COMPREPLY=()
 616     cur=${COMP_WORDS[COMP_CWORD]}
 617 
 618     # If we want an option, return the possible long options.
 619     case "$cur" in
 620         -*)     COMPREPLY=( $(_get_longopts $1 $cur ) ); return 0;;
 621     esac
 622 
 623     if [ $COMP_CWORD -eq 1 ]; then
 624         COMPREPLY=( $( compgen -W 'c t x u r d A' -- $cur ) )
 625         return 0
 626     fi
 627 
 628     case "${COMP_WORDS[1]}" in
 629         ?(-)c*f)
 630             COMPREPLY=( $( compgen -f $cur ) )
 631             return 0
 632             ;;
 633             +([^Izjy])f)
 634             ext='tar'
 635             regex=$ext
 636             ;;
 637         *z*f)
 638             ext='tar.gz'
 639             regex='t\(ar\.\)\(gz\|Z\)'
 640             ;;
 641         *[Ijy]*f)
 642             ext='t?(ar.)bz?(2)'
 643             regex='t\(ar\.\)bz2\?'
 644             ;;
 645         *)
 646             COMPREPLY=( $( compgen -f $cur ) )
 647             return 0
 648             ;;
 649 
 650     esac
 651 
 652     if [[ "$COMP_LINE" == tar*.$ext' '* ]]; then
 653         # Complete on files in tar file.
 654         #
 655         # Get name of tar file from command line.
 656         tar=$( echo "$COMP_LINE" | \
 657                sed -e 's|^.* \([^ ]*'$regex'\) .*$|\1|' )
 658         # Devise how to untar and list it.
 659         untar=t${COMP_WORDS[1]//[^Izjyf]/}
 660 
 661         COMPREPLY=( $( compgen -W "$( echo $( tar $untar $tar \
 662                     2>/dev/null ) )" -- "$cur" ) )
 663         return 0
 664 
 665     else
 666         # File completion on relevant files.
 667         COMPREPLY=( $( compgen -G $cur\*.$ext ) )
 668 
 669     fi
 670 
 671     return 0
 672 
 673 }
 674 
 675 complete -F _tar -o default tar
 676 
 677 _make()
 678 {
 679     local mdef makef makef_dir="." makef_inc gcmd cur prev i;
 680     COMPREPLY=();
 681     cur=${COMP_WORDS[COMP_CWORD]};
 682     prev=${COMP_WORDS[COMP_CWORD-1]};
 683     case "$prev" in
 684         -*f)
 685             COMPREPLY=($(compgen -f $cur ));
 686             return 0
 687         ;;
 688     esac;
 689     case "$cur" in
 690         -*)
 691             COMPREPLY=($(_get_longopts $1 $cur ));
 692             return 0
 693         ;;
 694     esac;
 695 
 696     # make reads `GNUmakefile', then `makefile', then `Makefile'
 697     if [ -f ${makef_dir}/GNUmakefile ]; then
 698         makef=${makef_dir}/GNUmakefile
 699     elif [ -f ${makef_dir}/makefile ]; then
 700         makef=${makef_dir}/makefile
 701     elif [ -f ${makef_dir}/Makefile ]; then
 702         makef=${makef_dir}/Makefile
 703     else
 704         makef=${makef_dir}/*.mk        # Local convention.
 705     fi
 706 
 707 
 708     # Before we scan for targets, see if a Makefile name was
 709     # specified with -f ...
 710     for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
 711         if [[ ${COMP_WORDS[i]} == -f ]]; then
 712            # eval for tilde expansion
 713            eval makef=${COMP_WORDS[i+1]}
 714            break
 715         fi
 716     done
 717     [ ! -f $makef ] && return 0
 718 
 719     # deal with included Makefiles
 720     makef_inc=$( grep -E '^-?include' $makef | \
 721     sed -e "s,^.* ,"$makef_dir"/," )
 722     for file in $makef_inc; do
 723         [ -f $file ] && makef="$makef $file"
 724     done
 725 
 726 
 727     # If we have a partial word to complete, restrict completions to
 728     # matches of that word.
 729     if [ -n "$cur" ]; then gcmd='grep "^$cur"' ; else gcmd=cat ; fi
 730 
 731     COMPREPLY=( $( awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \
 732                                 {split($1,A,/ /);for(i in A)print A[i]}' \
 733                                 $makef 2>/dev/null | eval $gcmd  ))
 734 
 735 }
 736 
 737 complete -F _make -X '+($*|*.[cho])' make gmake pmake
 738 
 739 
 740 
 741 
 742 _killall()
 743 {
 744     local cur prev
 745     COMPREPLY=()
 746     cur=${COMP_WORDS[COMP_CWORD]}
 747 
 748     # get a list of processes (the first sed evaluation
 749     # takes care of swapped out processes, the second
 750     # takes care of getting the basename of the process)
 751     COMPREPLY=( $( /usr/bin/ps -u $USER -o comm  | \
 752         sed -e '1,1d' -e 's#[]\[]##g' -e 's#^.*/##'| \
 753         awk '{if ($0 ~ /^'$cur'/) print $0}' ))
 754 
 755     return 0
 756 }
 757 
 758 complete -F _killall killall killps
 759 
 760 
 761 
 762 # A meta-command completion function for commands like sudo(8), which need to
 763 # first complete on a command, then complete according to that command's own
 764 # completion definition - currently not quite foolproof,
 765 # but still quite useful (By Ian McDonald, modified by me).
 766 
 767 
 768 _meta_comp()
 769 {
 770     local cur func cline cspec
 771 
 772     COMPREPLY=()
 773     cur=${COMP_WORDS[COMP_CWORD]}
 774     cmdline=${COMP_WORDS[@]}
 775     if [ $COMP_CWORD = 1 ]; then  
 776          COMPREPLY=( $( compgen -c $cur ) )
 777     else
 778         cmd=${COMP_WORDS[1]}            # Find command.
 779         cspec=$( complete -p ${cmd} )   # Find spec of that command.
 780 
 781         # COMP_CWORD and COMP_WORDS() are not read-only,
 782         # so we can set them before handing off to regular
 783         # completion routine:
 784         # Get current command line minus initial command,
 785         cline="${COMP_LINE#$1 }"
 786         # split current command line tokens into array,
 787         COMP_WORDS=( $cline )
 788         # set current token number to 1 less than now.
 789         COMP_CWORD=$(( $COMP_CWORD - 1 ))
 790         # If current arg is empty, add it to COMP_WORDS array
 791         # (otherwise that information will be lost).
 792         if [ -z $cur ]; then COMP_WORDS[COMP_CWORD]=""  ; fi
 793 
 794         if [ "${cspec%%-F *}" != "${cspec}" ]; then
 795       # if -F then get function:
 796             func=${cspec#*-F }
 797             func=${func%% *}
 798             eval $func $cline   # Evaluate it.
 799         else
 800             func=$( echo $cspec | sed -e 's/^complete//' -e 's/[^ ]*$//' )
 801             COMPREPLY=( $( eval compgen $func $cur ) )
 802         fi
 803 
 804     fi
 805     
 806 }
 807 
 808 
 809 complete -o default -F _meta_comp nohup \
 810 eval exec trace truss strace sotruss gdb
 811 complete -o default -F _meta_comp command type which man nice time
 812 
 813 # Local Variables:
 814 # mode:shell-script
 815 # sh-shell:bash
 816 # End: