# bash_completion - some programmable completion functions for bash 2.05a # # # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # RELEASE: 20020121 [ -n "$DEBUG" ] && set -v # Set a couple of useful vars # OS=$( uname -s ) RELEASE=$( uname -r ) # Turn on extended globbing and programmable completion shopt -s extglob progcomp # A lot of the following one-liners were taken directly from the # completion examples provided with the bash 2.04 source distribution # Make directory commands see only directories complete -d mkdir rmdir pushd # Make file commands see only files complete -f cat less more ln strip # the following section lists completions that are redefined later # START exclude -- do NOT remove this line complete -f -X '*.bz2' bzip2 complete -f -X '!*.bz2' bunzip2 complete -f -X '!*.zip' unzip complete -f -X '*.gz' gzip complete -f -X '*.Z' compress complete -f -X '!*.+(Z|gz|tgz|Gz)' gunzip zcat zmore complete -f -X '!*.Z' uncompress complete -f -X '!*.+(gif|jpg|jpeg|tif|tiff|png|GIF|JPG|TIF|TIFF|PNG|bmp)' ee xv complete -f -X '!*.+(?(e)ps|?(E)PS|?(e)ps.gz|pdf|PDF)' gv complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype complete -f -X '!*.+(pdf|PDF)' acroread xpdf complete -f -X '!*.texi*' makeinfo texi2dvi texi2html complete -f -X '!*.+(tex|TEX)' tex latex slitex jadetex pdfjadetex complete -f -X '!*.+(mp3|MP3)' mpg123 complete -f -X '!*.+(mpg|mpeg|avi|asf|vob|bin|vcd|ps|pes|fli|viv|rm|ram|yuv|mp3)' mplayer complete -f -X '!*.+(avi|asf)' avifile complete -f -X '!*.+(rm|ram)' realplay complete -f -X '!*.+(mpg|mpeg|avi|mov)' xanim complete -f -X '!*.+(ogg|OGG)' ogg123 complete -f -X '!*.+(mp3|MP3|ogg|OGG)' xmms gqmpeg freeamp # FINISH exclude -- do not remove this line # kill sees only signals complete -A signal -P '-' kill # user commands see only users complete -u finger su usermod userdel passwd # group commands see only groups complete -g groupmod groupdel passwd # bg completes with stopped jobs complete -A stopped -P '%' bg # other job commands complete -j -P '%' fg jobs disown # network commands complete with hostname complete -A hostname ssh rsh telnet rlogin ftp ping fping host traceroute \ nslookup # export and others complete with shell variables complete -v export local readonly unset # set completes with set options complete -A setopt set # shopt completes with shopt options complete -A shopt shopt # helptopics complete -A helptopic help # unalias completes with aliases complete -a unalias # bind completes with readline bindings (make this more intelligent) complete -A binding bind # Now we get to the meat of the file, the functions themselves. Some # of these are works in progress. Most assume GNU versions of the # tools in question and may require modifications for use on vanilla # UNIX systems. # # A couple of functions may have non-portable, Linux specific code in # them, but this will be noted where applicable # This function is handy for checking whether we have certain programs # on the system. No need for bulky functions in memory if we don't. # have() { unset -v have type $1 &> /dev/null [ $? = 0 ] && have="yes" } # GNU chown(1) completion. This should be expanded to allow the use of # ':' as well as '.' as the user.group separator. # _chown() { local cur prev user group i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # do not attempt completion if we're specifying an option [ "$cur" == -* ] && return 0 # first parameter on line or first since an option? if [ $COMP_CWORD = 1 ] || [[ "$prev" == -* ]]; then if [[ "$cur" == [a-zA-Z]*.* ]]; then user=${cur%.*} group=${cur#*.} COMPREPLY=( $( compgen -g $group ) ) for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=$user.${COMPREPLY[i]} done else COMPREPLY=( $( compgen -u $cur -S '.' ) ) fi fi return 0 } complete -F _chown -o default chown # chgrp(1) completion # _chgrp() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # do not attempt completion if we're specifying an option [ "$cur" == -* ] && return 0 # first parameter on line or first since an option? if [ $COMP_CWORD = 1 ] || [[ "$prev" == -* ]]; then COMPREPLY=( $( compgen -g $cur ) ) fi return 0 } complete -F _chgrp -o default chgrp # umount(8) completion. This relies on the mount point being the third # space-delimited field in the output of mount(8) # _umount() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} # could rewrite the cut | grep to be a sed command, but this is # clearer and doesn't result in much overhead COMPREPLY=( $( mount | cut -d' ' -f 3 | grep ^$cur) ) return 0 } complete -F _umount -o filenames umount # mount(8) completion. This will pull a list of possible mounts out of # /etc/fstab, unless the word being completed contains a ':', which # would indicate the specification of an NFS server. In that case, we # query the server for a list of all available exports and complete on # that instead. # _mount() { local cur i sm COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} for i in {,/usr}/sbin/showmount; do [ -x $i ] && sm=$i && break; done if [ -n "$sm" ] && [[ "$cur" == *:* ]]; then COMPREPLY=( $( $sm -e --no-headers ${cur%%:*} | \ grep ^${cur#*:} | awk '{print $1}' ) ) else COMPREPLY=( $( awk '{if ($2 ~ /\//) print $2}' /etc/fstab | \ grep ^$cur ) ) fi return 0 } complete -F _mount -o default mount # Linux rmmod(1) completion. This completes on a list of all currently # installed kernel modules. # [ $OS = Linux ] && _rmmod() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $( /sbin/lsmod | \ awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' ) ) return 0 } [ $OS = Linux ] && complete -F _rmmod rmmod # Linux insmod(8) & modprobe(8) completion. This completes on a list of all # available modules for the version of the kernel currently running. # [ $OS = Linux ] && _insmod() { local cur prev modpath COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} modpath=/lib/modules/`uname -r` # behave like lsmod for modprobe -r if [ ${COMP_WORDS[0]} = "modprobe" ] && [ "${COMP_WORDS[1]}" = "-r" ]; then COMPREPLY=( $( /sbin/lsmod | \ awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}' ) ) return 0 fi # do filename completion if we're giving a path to a module if [[ "$cur" == /* ]]; then COMPREPLY=( $( compgen -f $cur ) ) return 0 fi if [ $COMP_CWORD -gt 1 ]; then # do module parameter completion COMPREPLY=( $( /sbin/modinfo -p ${COMP_WORDS[1]} | \ awk '{if ($1 ~ /^'$cur'/) print $1}' ) ) else # do module name completion COMPREPLY=( $( \ls -R $modpath | \ sed -ne 's/^\('$cur'.*\)\.o$/\1/p') ) fi return 0 } [ $OS = Linux ] && complete -F _insmod -o filenames insmod modprobe # man(1) completion. This is Linux specific, in that 'man
' # is the expected syntax. This allows one to do something like # 'man 3 str' to obtain a list of all string handling syscalls on # the system. # [ $OS = Linux ] && _man() { local cur prev cmd COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # default completion if parameter contains / [[ "$cur" == */* ]] && return 0 # default to command completion if no man.config if [ ! -f /etc/man.config ]; then COMPREPLY=( $( compgen -c $cur ) ) return 0 fi if [[ "$prev" == [0-9ln] ]]; then # churn out a string of paths to search, with * appended to $cur cmd=`awk '{if ($1 ~ /^MANPATH/) \ print $(NF)"/man'$prev'/'$cur'*"}' /etc/man.config | \ sort -u` # strip off * from paths ending in /* cmd=${cmd//\/\\*/\/} # redirect stderr for when path doesn't exist cmd="ls $cmd 2>/dev/null" COMPREPLY=( $( eval $cmd ) ) # get basename of man pages COMPREPLY=( ${COMPREPLY[@]##*/} ) # strip suffix from man pages COMPREPLY=( ${COMPREPLY[@]%.gz} ) COMPREPLY=( ${COMPREPLY[@]%.*} ) else cmd=`awk '{if ($1 ~ /^MANPATH/) \ print $(NF)"/man?/'$cur'*"}' /etc/man.config | sort -u` cmd=${cmd//\/\\*/\/} cmd="ls $cmd 2>/dev/null" COMPREPLY=( $( eval $cmd ) ) COMPREPLY=( ${COMPREPLY[@]##*/} ) COMPREPLY=( ${COMPREPLY[@]%.gz} ) COMPREPLY=( ${COMPREPLY[@]%.*} $( compgen -G $cur\*.[0-9ln] ) ) fi return 0 } [ $OS = Linux ] && complete -F _man -o default man # Linux killall(1) completion. This wouldn't be much use on, say, # Solaris, where killall does exactly that: kills ALL processes. # # This could be improved. For example, it currently doesn't take # command line options into account # _killall() { local cur prev i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} if [[ "$prev" == -[A-Z0-9]* ]]; then # get a list of processes (the gensub() in the awk takes care # of getting the basename of the process, the first sed # evaluation takes care of swapped out processes, and the # second takes care of getting the basename of the process) COMPREPLY=( $( ps ahx | sed -e 's#[]\[()]##g' | \ awk '{if (gensub("^.*/","",1,$5) ~ /^'$cur'/) print $5}' | \ sed -e 's#^.*/##' ) ) return 0 fi # first parameter can be either a signal or a process if [ $COMP_CWORD = 1 ]; then # standard signal completion is rather braindead, so we need # to hack around to get what we want here, which is to # complete on a dash, followed by the signal name minus # the SIG prefix COMPREPLY=( $( compgen -A signal SIG${cur#-} )) for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=-${COMPREPLY[i]#SIG} done fi # get processes, adding to signals if applicable COMPREPLY=( ${COMPREPLY[*]} $( ps ahx | sed -e 's#[]\[()]##g' | \ awk '{if (gensub("^.*/","",1,$5) ~ /^'$cur'/) print $5}' | \ sed -e 's#^.*/##' )) return 0 } complete -F _killall killall # GNU find(1) completion. This makes heavy use of ksh style extended # globs and contains Linux specific code for completing the parameter # to the -fstype option. # _find() { local cur prev i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]#-} prev=${COMP_WORDS[COMP_CWORD-1]} case "$prev" in -@(max|min)depth) COMPREPLY=( $( compgen -W '0 1 2 3 4 5 6 7 8 9' ) ) return 0 ;; -?(a)newer|-fls|-fprint?(0|f)) COMPREPLY=( $( compgen -f $cur ) ) return 0 ;; -fstype) # this is highly non-portable COMPREPLY=( $( cut -d$'\t' -f 2 /proc/filesystems | grep ^$cur ) ) return 0 ;; -gid) COMPREPLY=( $( awk 'BEGIN {FS=":"} \ {if ($3 ~ /^'$cur'/) print $3}' /etc/group ) ) return 0 ;; -group) COMPREPLY=( $( compgen -g $cur ) ) return 0 ;; -?(x)type) COMPREPLY=( $( compgen -W 'b c d p f l s' $cur ) ) return 0 ;; -uid) COMPREPLY=( $( awk 'BEGIN {FS=":"} \ {if ($3 ~ /^'$cur'/) print $3}' /etc/passwd ) ) return 0 ;; -user) COMPREPLY=( $( compgen -u $cur ) ) return 0 ;; -[acm]min|-[acm]time|-?(i)?(l)name|-inum|-?(i)path|-?(i)regex| \ -links|-perm|-size|-used|-exec|-ok|-printf) # do nothing, just wait for a parameter to be given return 0 ;; esac # complete using basic options ($cur has had its dash removed here, # as otherwise compgen will bomb out with an error, since it thinks # the dash is an option to itself) COMPREPLY=( $( compgen -W 'daystart depth follow help maxdepth \ mindepth mount noleaf version xdev amin anewer atime \ cmin cnewer ctime empty false fstype gid group ilname \ iname inum ipath iregex links lname mmin mtime name \ newer nouser nogroup perm regex size true type uid \ used user xtype exec fls fprint fprint0 fprintf ok \ print print0 printf prune ls' $cur ) ) # this removes any options from the list of completions that have # already been specified somewhere on the command line. COMPREPLY=( $( echo "${COMP_WORDS[@]}-" | \ (while read -d '-' i; do [ "$i" == "" ] && continue # flatten array with spaces on either side, # otherwise we cannot grep on word boundaries of # first and last word COMPREPLY=" ${COMPREPLY[@]} " # remove word from list of completions COMPREPLY=( ${COMPREPLY/ ${i%% *} / } ) done echo ${COMPREPLY[@]}) ) ) # put dashes back for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=-${COMPREPLY[i]} done return 0 } complete -F _find -o dirnames find # Linux ifconfig(8) completion # [ $OS = Linux ] && _ifconfig() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} case "${COMP_WORDS[1]}" in -|*[0-9]*) COMPREPLY=( $( compgen -W '-a up down arp promisc allmulti \ metric mtu dstaddr netmask add del \ tunnel irq io_addr mem_start media \ broadcast pointopoint hw multicast \ address txqueuelen' $cur )) COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \ (while read -d ' ' i; do [ "$i" == "" ] && continue # flatten array with spaces on either side, # otherwise we cannot grep on word # boundaries of first and last word COMPREPLY=" ${COMPREPLY[@]} " # remove word from list of completions COMPREPLY=( ${COMPREPLY/ $i / } ) done echo ${COMPREPLY[@]}) ) ) return 0 ;; esac COMPREPLY=( $( ifconfig -a | sed -ne 's/^\('$cur'[^ ]*\).*$/\1/p' )) } [ $OS = Linux ] && complete -F _ifconfig ifconfig # RedHat Linux if{up,down} completion by Frank Sweetser # [ $OS = Linux ] && ( have ifup || have ifdown ) && _ifupdown() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} if [ $COMP_CWORD = 1 ] ; then COMPREPLY=( $( \ls /etc/sysconfig/network-scripts/ifcfg-* | sed -ne 's/.*ifcfg-\('$cur'.*\)/\1/p' ) ) fi return 0 } [ $OS = Linux ] && have ifup && complete -F _ifupdown ifup ifdown # Linux ipsec(8) completion (for FreeS/WAN). Basic. # [ $OS = Linux ] && have ipsec && _ipsec() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} if [ $COMP_CWORD = 1 ]; then COMPREPLY=( $( compgen -W 'auto barf eroute klipsdebug look manual \ pluto ranbits rsasigkey setup showdefaults \ showhostkey spi spigrp tncfg whack' $cur )) return 0 fi case ${COMP_WORDS[1]} in auto) COMPREPLY=( $( compgen -W '--asynchronous --up --add --delete \ --replace --down --route --unroute \ --ready --status --rereadsecrets' $cur ) ) return 0 ;; manual) COMPREPLY=( $( compgen -W '--up --down --route --unroute \ --union' $cur ) ) return 0 ;; ranbits) COMPREPLY=( $( compgen -W '--quick --continuous --bytes' $cur ) ) return 0 ;; setup) COMPREPLY=( $( compgen -W '--start --stop --restart' $cur ) ) return 0 ;; *) return 0 ;; esac return 0 } [ $OS = Linux ] && [ "$have" ] && complete -F _ipsec ipsec # cvs(1) completion # _cvs() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} if [ $COMP_CWORD = 1 ] || [[ "$prev" == -* ]]; then COMPREPLY=( $( compgen -W 'add admin checkout commit diff \ export history import log rdiff release remove rtag status \ tag update' $cur )) fi return 0 } complete -F _cvs -o default cvs # rpm(8) completion. This is quite comprehensive now and covers rpm 4.x # have rpm && _rpm() { dashify() { local i for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do if [ ${#COMPREPLY[i]} -le 2 ]; then COMPREPLY[i]=-${COMPREPLY[i]} else COMPREPLY[i]=--${COMPREPLY[i]} fi done } add_package_list() { if [ -f /var/log/rpmpkgs ]; then # using RHL 7.2 - this is quicker than querying the DB COMPREPLY=( ${COMPREPLY[@]} $( sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.]\+.*\.rpm$/\1/p' /var/log/rpmpkgs ) ) else COMPREPLY=( ${COMPREPLY[@]} $( rpm -qa | \ sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9a-z.]\+$/\1/p' ) ) fi } file_glob() { local suffix # get extension of current word, if relevant suffix=${cur##*.} # nullify it if it's not a substring of the extension we're # completing on [ "$suffix" != "${1:0:${#suffix}}" ] && suffix="" COMPREPLY=( ${COMPREPLY[@]} $( compgen -G $cur\*${1:${#suffix}} ) ) # directory completion if all else fails and current word # contains a slash if [ ${#COMPREPLY[@]} = 0 ] && [[ $cur == */* ]]; then COMPREPLY=( $( compgen -d $cur ) ) fi } local cur cur_nodash prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} cur_nodash=${cur#-} prev=${COMP_WORDS[COMP_CWORD-1]} if [ $COMP_CWORD = 1 ]; then # first parameter on line case "$cur" in -b*) COMPREPLY=( $( compgen -W 'ba bb bc bi bl bp bs' \ $cur_nodash ) ) dashify return 0 ;; -t*) COMPREPLY=( $( compgen -W 'ta tb tc ti tl tp ts' \ $cur_nodash ) ) dashify return 0 ;; --*) COMPREPLY=( $( compgen -W 'help version initdb \ checksig recompile rebuild resign addsign rebuilddb \ showrc setperms setugids tarbuild eval install \ upgrade query freshen erase verify querytags rmsource' \ ${cur_nodash#-} ) ) dashify return 0 ;; *) COMPREPLY=( $( compgen -W 'b e F i q t U V' \ $cur_nodash ) ) dashify return 0 ;; esac fi case "$prev" in --@(db|exclude)path|prefix|relocate|root) COMPREPLY=( $( compgen -d $cur ) ) return 0 ;; --eval) # get a list of macros COMPREPLY=( $( sed -ne 's/^\(%'${cur#\%}'[^ '$'\t'']*\).*$/\1/p' \ /usr/lib/rpm/macros ) ) return 0 ;; --pipe) COMPREPLY=( $( compgen -c $cur ) ) return 0 ;; --rcfile) COMPREPLY=( $( compgen -f $cur ) ) return 0 ;; --specfile) # complete on .spec files file_glob spec return 0 ;; --whatprovides) # complete on capabilities COMPREPLY=( $( rpm -qa --queryformat '%{providename}\n' | grep ^$cur ) ) return 0 ;; --whatrequires) # complete on capabilities COMPREPLY=( $( rpm -qa --queryformat '%{requirename}\n' | grep ^$cur ) ) return 0 ;; esac case "${COMP_WORDS[1]}" in -@([iFU]*|-install|-freshen|-upgrade)) # complete on list of relevant options COMPREPLY=( $( compgen -W 'percent force test replacepkgs \ replacefiles root excludedocs includedocs noscripts rcfile \ ignorearch dbpath prefix ignoreos nodeps allfiles ftpproxy \ ftpport justdb httpproxy httpport noorder relocate badreloc \ notriggers excludepath ignoresize oldpackage define eval \ pipe queryformat repackage' ${cur_nodash#-} )) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 # add a list of RPMS to possible completions file_glob rpm return 0 ;; -qp*) # complete on list of relevant options COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \ whatrequires requires triggeredby ftpport ftpproxy httpproxy \ httpport provides triggers dump changelog dbpath filesbypkg \ define eval pipe showrc info list state docfiles \ configfiles queryformat conflicts obsoletes' ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 # add a list of RPMS to possible completions file_glob rpm return 0 ;; -*f) # standard filename completion COMPREPLY=( $( compgen -f $cur ) ) return 0 ;; -@(e|-erase)) # complete on list of relevant options COMPREPLY=( $( compgen -W 'allmatches noscripts notriggers \ nodeps test repackage' ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 add_package_list return 0 ;; -q*) # complete on list of relevant options COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \ whatrequires requires triggeredby ftpport ftpproxy httpproxy \ httpport provides triggers dump changelog dbpath specfile \ querybynumber last filesbypkg define eval pipe showrc info \ list state docfiles configfiles queryformat conflicts \ obsoletes' ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 # don't complete on packages if we are querying all packages [[ ${COMP_WORDS[1]} == -qa* ]] && return 0 add_package_list return 0 ;; -@(K|-checksig)) # complete on list of relevant options COMPREPLY=( $( compgen -W 'nopgp nogpg nomd5' \ ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 # add a list of RPMS to possible completions file_glob rpm return 0 ;; -@([Vy]*|-verify)) # complete on list of relevant options COMPREPLY=( $( compgen -W 'root rcfile dbpath nodeps nofiles \ noscripts nomd5' ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 add_package_list return 0 ;; -[bt]*) # complete on list of relevant options COMPREPLY=( $( compgen -W 'short-circuit timecheck clean \ rmsource test sign buildroot target buildarch buildos \ nobuild' ${cur_nodash#-} ) ) dashify # return if $cur is an option [[ "$cur" == -* ]] && return 0 if [[ ${COMP_WORDS[1]} == -b* ]]; then # complete on .spec files file_glob spec else # complete on .tar files COMPREPLY=( $( compgen -G $cur\*.+(tgz|tar.+(gz|bz2)) ) ) fi return 0 ;; --re@(build|compile)) # complete on source RPMs COMPREPLY=( $( compgen -G $cur\*.src.rpm ) ) return 0 ;; --tarbuild) # complete on tarred sources COMPREPLY=( $( compgen -G $cur\*.+(tgz|tar.+(gz|bz2)) ) ) return 0 ;; --@(re|add)sign) # complete on RPMs file_glob rpm return 0 ;; --set@(perms|gids)) add_package_list return 0 ;; --rmsource) file_glob spec return 0 ;; -*g) # package group completion local IFS=$'\t' # remove trailing backslash, or grep will complain cur=${cur%'\'} COMPREPLY=( $( rpm -qa --queryformat '%{group}\n' | \ grep ^$cur ) ) # backslash escape spaces and translate newlines to tabs COMPREPLY=( $( echo ${COMPREPLY[@]} | sed 's/ /\\ /g' | \ tr '\n' '\t' ) ) return 0 ;; esac return 0 } [ "$have" ] && complete -F _rpm -o filenames rpm # Debian Linux apt-get(8) completion. # have apt-get && _apt-get() { local cur prev special i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} for (( i=0; i < ${#COMP_WORDS}-1; i++ )); do if [[ ${COMP_WORDS[i]} == @(install|remove|source) ]]; then special=${COMP_WORDS[i]} fi done if [ -n "$special" ]; then case $special in @(install|remove|source)) COMPREPLY=( $( apt-cache pkgnames $cur ) ) return 0 ;; esac fi if [[ "$prev" == -*c ]] || [ "$prev" = --config-file ]; then COMPREPLY=( $( compgen -f $cur ) ) else COMPREPLY=( $( compgen -W 'update upgrade dselect-upgrade \ dist-upgrade install remove source check \ clean autoclean -d -f -h -v -m -q -s -y -u \ -b -c -o --download-only --fix-broken --help \ --version --ignore-missing --fix-missing \ --no-download --quiet --simulate \ --just-print --dry-run --recon --no-act \ --yes --assume-yes --show-upgraded \ --compile --build --ignore-hold \ --no-upgrade --force-yes --print-uris \ --purge --reinstall --list-cleanup \ --trivial-only --no-remove --diff-only \ --tar-only --config-file --option ' | \ grep ^$cur ) ) fi return 0 } [ "$have" ] && complete -F _apt-get -o filenames apt-get # Debian Linux apt-cache(8) completion. # have apt-cache && _apt-cache() { local cur prev special i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} for (( i=0; i < ${#COMP_WORDS}-1; i++ )); do if [[ ${COMP_WORDS[i]} == @(add|showpkg) ]]; then special=${COMP_WORDS[i]} fi done if [ -n "$special" ]; then case $special in add) COMPREPLY=( $( compgen -f $cur ) ) return 0 ;; showpkg) COMPREPLY=( $( apt-cache pkgnames $cur ) ) return 0 ;; esac fi if [[ "$prev" == -*c ]] || [ "$prev" = --config-file ]; then COMPREPLY=( $( compgen -f $cur ) ) else COMPREPLY=( $( compgen -W 'add gencaches showpkg stats dump \ dumpavail unmet check search show showpkg \ depends pkgnames -h -v -p -s -q -i -f -a -g -c \ -o --help --version --pkg-cache --src-cache \ --quiet --important --full --all-versions \ --no-generate --names-only --all-names \ --config-file --option' | grep ^$cur ) ) fi return 0 } [ "$have" ] && complete -F _apt-cache -o filenames apt-cache # chsh(1) completion # _chsh() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} if [ "$prev" = "-s" ]; then COMPREPLY=( $( chsh -l | grep ^$cur ) ) else COMPREPLY=( $( compgen -u $cur ) ) fi return 0 } complete -F _chsh chsh # chkconfig(8) completion # have chkconfig && _chkconfig() { local cur prev i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} cur_nodash=${cur#--} prev=${COMP_WORDS[COMP_CWORD-1]} if [ $COMP_CWORD = 1 ]; then COMPREPLY=( $( compgen -W 'list add del level' $cur_nodash ) ) for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=--${COMPREPLY[i]} done return 0 fi if [ $COMP_CWORD -eq 4 ]; then COMPREPLY=( $( compgen -W 'on off reset' $cur ) ) return 0 fi case "$prev" in @([1-6]|--@(list|add|del))) COMPREPLY=( $( compgen -W "`(cd /etc/rc.d/init.d; echo *)`" \ $cur) ) return 0 ;; --level) COMPREPLY=( $( compgen -W '1 2 3 4 5 6' $cur ) ) return 0 ;; esac return 0 } [ "$have" ] && complete -F _chkconfig chkconfig # This function performs host completion based on ssh's known_hosts files, # defaulting to standard host completion if they don't exist. # _known_hosts() { local cur kh user COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@} kh=() [ -r /etc/known_hosts ] && kh[0]=/etc/known_hosts [ -r /etc/known_hosts2 ] && kh[1]=/etc/known_hosts2 [ -r ~/.ssh/known_hosts ] && kh[2]=~/.ssh/known_hosts [ -r ~/.ssh/known_hosts2 ] && kh[3]=~/.ssh/known_hosts2 # If we have known_hosts files to use if [ ${#kh[@]} -gt 0 ]; then # Escape slashes and dots in paths for awk cur=${cur//\//\\\/} cur=${cur//\./\\\.} if [[ "$cur" == [0-9]*.* ]]; then # Digits followed by a dot - just search for that cur="^$cur.*" elif [[ "$cur" == [0-9]* ]]; then # Digits followed by no dot - search for digits followed # by a dot cur="^$cur.*\." elif [ -z "$cur" ]; then # A blank - search for a dot or an alpha character cur="[a-z.]" else cur="^$cur" fi # FS needs to look for a comma separated list COMPREPLY=( $( awk 'BEGIN {FS=","} {for (i=1; i<=2; ++i) { \ gsub(" .*$", "", $i); \ if ($i ~ /'$cur'/) {print $i} \ }}' ${kh[@]} ) ) for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do COMPREPLY[i]=$user${COMPREPLY[i]} done else # Just do normal hostname completion COMPREPLY=( $( compgen -A hostname $cur ) ) fi return 0 } complete -F _known_hosts traceroute ping fping telnet host nslookup # ssh(1) completion. Should be able to improve this with user@host notation, # but the '@' seems to trigger some kind of bug in bash's completion. # have ssh && _ssh() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} case "$prev" in -*c) COMPREPLY=( $( compgen -W 'blowfish 3des 3des-cbc blowfish-cbc \ arcfour cast128-cbc' $cur ) ) ;; -*l) COMPREPLY=( $( compgen -u $cur ) ) ;; *) _known_hosts [ $COMP_CWORD = 1 ] || \ COMPREPLY=( ${COMPREPLY[@]} $( compgen -c $cur ) ) esac return 0 } [ "$have" ] && shopt -u hostcomplete && complete -F _ssh ssh slogin sftp have scp && _scp() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} _known_hosts COMPREPLY=( ${COMPREPLY[@]} $( compgen -f $cur ) ) return 0 } [ "$have" ] && complete -o filenames -F _scp scp # Linux route(8) completion. This could be improved by adding address family # completion for -A, etc. # _route() { local cur prev COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} if [ "$prev" = dev ]; then COMPREPLY=( $( ifconfig -a | sed -ne 's/^\('$cur'[^ ]*\).*$/\1/p' )) return 0 fi # Must use grep here, otherwise $cur will cause compgen to barf, if # it begins with a hyphen COMPREPLY=( $( compgen -W 'add del -host -net netmask metric mss \ window irtt reject mod dyn reinstate dev' | \ grep ^$cur ) ) COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \ (while read -d ' ' i; do [ "$i" == "" ] && continue # flatten array with spaces on either side, # otherwise we cannot grep on word # boundaries of first and last word COMPREPLY=" ${COMPREPLY[@]} " # remove word from list of completions COMPREPLY=( ${COMPREPLY/ $i / } ) done echo ${COMPREPLY[@]}) ) ) return 0 } complete -F _route route # GNU make(1) completion (adapted from the example supplied with the bash 2.04 # source code) # _make() { local mdef makef gcmd cur prev i COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # if prev argument is -f, return possible filename completions. # we could be a little smarter here and return matches against # `makefile Makefile *.mk', whatever exists if [[ "$prev" == -*f ]]; then COMPREPLY=( $( compgen -f $cur ) ) return 0 fi # if we want an option, return the possible posix options if [[ "$cur" == - ]]; then COMPREPLY=( $( compgen -W '-e -f -i -k -n -p -q -r -S -s -t' | grep ^$cur ) ) return 0 fi # make reads `makefile' before `Makefile' if [ -f makefile ]; then mdef=makefile elif [ -f Makefile ]; then mdef=Makefile else mdef=*.mk # local convention fi # before we scan for targets, see if a makefile name was specified # with -f for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do if [[ ${COMP_WORDS[i]} == -*f ]]; then eval makef=${COMP_WORDS[i+1]} # eval for tilde expansion break fi done [ -z "$makef" ] && makef=$mdef # if we have a partial word to complete, restrict completions to # matches of that word [ -n "$2" ] && gcmd='grep "^$2"' || gcmd=cat # if we don't want to use *.mk, we can take out the cat and use # test -f $makef and input redirection COMPREPLY=( $( cat $makef 2>/dev/null | \ awk 'BEGIN {FS=":"} /^[^.# ][^=]*:/ {print $1}' | \ eval $gcmd ) ) # default to filename completion if all else failed if [ ${#COMPREPLY[@]} = 0 ]; then COMPREPLY=( $( compgen -f $cur ) ) fi return 0 } complete -F _make -X '+($*|*.[cho])' -o filenames make gmake pmake # Red Hat Linux service completion. This completes on a list of all available # service scripts in the SysV init.d directory, followed by that script's # available commands # have service && _service() { local cur sysvdir COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d \ || sysvdir=/etc/init.d #[[ "$cur" == -* ]] && return 0 if [ $COMP_CWORD = 1 ]; then COMPREPLY=( $( compgen -W '`echo $sysvdir/!(*.rpmsave|*.rpmorig)`' ) ) COMPREPLY=( $( compgen -W '${COMPREPLY[@]#$sysvdir/}' $cur ) ) else COMPREPLY=( $( compgen -W '`sed -ne "y/|/ /; \ s/^.*Usage.*{\(.*\)}.*$/\1/p" \ $sysvdir/${COMP_WORDS[1]}`' $cur ) ) fi return 0 } [ "$have" ] && complete -F _service service # The beginnings of a completion function for GNU tar(1) # _tar() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} if [[ ${COMP_WORDS[1]} == c*f ]]; then COMPREPLY=( $( compgen -f $cur ) ) elif [[ ${COMP_WORDS[1]} == +([^zj])f ]]; then COMPREPLY=( $( compgen -G $cur\*.tar ) ) elif [[ ${COMP_WORDS[1]} == *z*f ]]; then COMPREPLY=( $( compgen -G $cur\*.t?(ar.)gz ) ) elif [[ ${COMP_WORDS[1]} == *j*f ]]; then COMPREPLY=( $( compgen -G $cur\*.tar.bz2 ) ) fi return 0 } complete -F _tar -o default tar # Linux iptables(8) completion # have iptables && _iptables() { local cur prev table chain COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} chain='s/^Chain \([^ ]\+\).*$/\1/p' if [[ $COMP_LINE == *-t\ *filter* ]]; then table="-t filter" elif [[ $COMP_LINE == *-t\ *nat* ]]; then table="-t nat" elif [[ $COMP_LINE == *-t\ *mangle* ]]; then table="-t mangle" fi case "$prev" in -*[AIDPFXL]) COMPREPLY=( $( compgen -W '`iptables $table -nL | sed -ne "s/^Chain \([^ ]\+\).*$/\1/p"`' $cur ) ) ;; -*t) COMPREPLY=( $( compgen -W 'nat filter mangle' $cur ) ) ;; -j) if [ "$table" = "-t filter" -o "$table" = "" ]; then COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \ `iptables $table -nL | sed -ne "$chain" \ -e "s/INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING//"`' \ $cur ) ) elif [ "$table" = "-t nat" ]; then COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \ MIRROR SNAT DNAT MASQUERADE `iptables $table -nL | \ sed -ne "$chain" -e "s/OUTPUT|PREROUTING|POSTROUTING//"`' \ $cur ) ) elif [ "$table" = "-t mangle" ]; then COMPREPLY=( $( compgen -W 'ACCEPT DROP LOG ULOG REJECT \ MARK TOS `iptables $table -nL | sed -ne "$chain" \ -e "s/INPUT|OUTPUT|FORWARD|PREROUTING|POSTROUTING//"`' \ $cur ) ) fi ;; *) ;; esac } [ "$have" ] && complete -F _iptables iptables # tcpdump(8) completion # have tcpdump && _tcpdump() { local cur COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $( compgen -W 'host net port src dst ether gateway less greater' $cur ) ) } [ "$have" ] && complete -F _tcpdump tcpdump # This meta-cd function observes the CDPATH variable, so that cd additionally # completes on directories under those specified in CDPATH. # _cd() { local IFS=$'\t\n' cur=${COMP_WORDS[COMP_CWORD]} dirs=() i # expand ~username type directory specifications if [[ "$cur" == \~*/* ]]; then eval cur=$cur elif [[ "$cur" == \~* ]]; then cur=${cur#\~} COMPREPLY=( $( compgen -P '~' -u $cur ) ) return 0 fi # standard dir completion if parameter starts with /, ./ or ../ if [[ "$cur" == ?(.)?(.)/* ]]; then COMPREPLY=( $( compgen -d $cur ) ) return 0 fi if [ -n "$CDPATH" ]; then # we have a CDPATH, so loop on its contents for i in ${CDPATH//:/ }; do # create an array of matched subdirs dirs=( $( compgen -d $i/$cur ) ) # add subdirs to list of completions as necessary [ ${#dirs[@]} ] && COMPREPLY=( ${COMPREPLY[@]} ${dirs[@]#$i/}) done fi COMPREPLY=( ${COMPREPLY[@]} $( compgen -d $cur ) ) return 0 } complete -F _cd -o filenames cd # A meta-command completion function for commands like sudo(8), which need to # first complete on a command, then complete according to that command's own # completion definition - currently not quite foolproof, but works well # _command() { local cur func cline cspec COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} if [ $COMP_CWORD = 1 ]; then COMPREPLY=( $( compgen -c $cur ) ) elif complete -p ${COMP_WORDS[1]} >/dev/null; then cspec=$( complete -p ${COMP_WORDS[1]} ) if [ "${cspec#*-F }" != "$cspec" ]; then # complete -F # # COMP_CWORD and COMP_WORDS() are not read-only, # so we can set them before handing off to regular # completion routine # set current token number to 1 less than now COMP_CWORD=$(( $COMP_CWORD - 1 )) # get function name func=${cspec#*-F } func=${func%% *} # get current command line minus initial command cline="${COMP_LINE#$1 }" # split current command line tokens into array COMP_WORDS=( $cline ) # call regular completion function $func "$cline" elif [ "${cspec#*-[abcdefgjkvu]}" != "$cspec" ]; then # complete -[abcdefgjkvu] func=$( echo $cspec | \ sed -e 's/^.*\(-[abcdefgjkvu]\).*$/\1/' ) COMPREPLY=( $( compgen $func $cur ) ) elif [ "${cspec#*-A}" != "$cspec" ]; then # complete -A func=${cspec#*-A } func=${func%% *} COMPREPLY=( $( compgen -A $func $cur ) ) fi fi } complete -F _command -o filenames type nohup exec nice eval strace sudo gdb # Basic Perforce completion by Frank Cusack (frank@google.com) # have p4 && _p4() { local cur prev prev2 p4commands p4filetypes COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} # rename isn't really a command p4commands="add admin branch branches change changes client \ clients counter counters delete depot depots describe \ diff diff2 dirs edit filelog files fix fixes flush \ fstat group groups have help info integrate integrated \ job jobs jobspec label labels labelsync lock obliterate \ opened passwd print protect rename reopen resolve \ resolved revert review reviews set submit sync triggers \ typemap unlock user users verify where" p4filetypes="ctext cxtext ktext kxtext ltext tempobj ubinary \ uresource uxbinary xbinary xltext xtempobj xtext \ text binary resource" if [ $COMP_CWORD = 1 ]; then COMPREPLY=( $( compgen -W "$p4commands" $cur ) ) elif [ $COMP_CWORD -eq 2 ]; then case "$prev" in help) COMPREPLY=( $( compgen -W "simple commands \ environment filetypes jobview revisions \ usage views $p4commands" $cur ) ) ;; admin) COMPREPLY=( $( compgen -W "checkpoint stop" $cur ) ) ;; *) ;; esac elif [ $COMP_CWORD -gt 2 ]; then prev2=${COMP_WORDS[COMP_CWORD-2]} case "$prev" in -t) case "$prev2" in add|edit|reopen) COMPREPLY=( $(compgen -W "$p4filetypes" $cur) ) ;; *) ;; esac ;; *) ;; esac fi return 0 } [ "$have" ] && complete -F _p4 -o default p4 g4 # ant completion is modified from the original submitted by # Claus-Peter Klas # have ant && _ant_targets() { COMPREPLY=() local gcmd # if we have a partial word to complete, restrict completions to # matches of that word [ ! -f build.xml ] && return 0 [ -n "$2" ] && gcmd='grep "^$2"' || gcmd=cat COMPREPLY=( $( awk 'BEGIN {FS="\""} /\]'*) return 1;; *[\<\>]*) return 0;; *) return 1;; esac } # _redir_test tests the current word ($1) and the previous word ($2) for # redirection operators and does filename completion on the current word # if either one contains a redirection operator _redir_test() { if _redir_op "$1" ; then COMPREPLY=( $( compgen -f "$1" ) ) return 0 elif _redir_op "$2" ; then COMPREPLY=( $( compgen -f "$1" ) ) return 0 fi return 1 } _configure_func () { case "$2" in -*) ;; *) return ;; esac case "$1" in \~*) eval cmd=$1 ;; *) cmd="$1" ;; esac COMPREPLY=( $( "$cmd" --help | sed -ne 's/^ *\('$2'[^ '$'\t'',[]\+\).*$/\1/p' ) ) } complete -F _configure_func configure _file_and_dir() { local IFS cur xspec IFS=$'\t\n' COMPREPLY=() cur=${COMP_WORDS[COMP_CWORD]#-} # get first exclusion compspec that matches this command xspec=$( sed -ne '/ '$1'/{p;q;}' /etc/bash_completion ) # prune to leave nothing but the -X spec xspec=${xspec#*-X } xspec=${xspec%% *} COMPREPLY=( $( eval compgen -f -X "$xspec" $cur ) $( compgen -d $cur ) ) } list=( $( sed -ne '/^# START exclude/,/^# FINISH exclude/p' \ /etc/bash_completion | \ # read exclusion compspecs ( while read line do line=${line%# START exclude*} line=${line%# FINISH exclude*} line=${line##*\'} list=( ${list[@]} $line ) done echo ${list[@]} ) ) ) # remove previous compspecs if [ ${#list[@]} -gt 0 ]; then eval complete -r ${list[@]} # install new compspecs eval complete -F _file_and_dir -o filenames ${list[@]} fi unset list[@] # source user completion file [ -f ~/.bash_completion ] && . ~/.bash_completion unset -f have unset OS RELEASE have