_reprepro() { local cur prev commands options noargoptions i state cmd ignores hiddencommands commands codenames confdir outdir basedir architectures components importrules snapshots confdir="" basedir="" outdir="" distdir="" # for parsing configs consider: # - command line arguments take priority over /options take priority over environment variables # - all the ways to set confdir may start with '+b/' to denote the basedir to be used. # - basedir might also be set in /options (which obviously does not change where this file is) function parse_config() { local conffile distfile if [[ -n "$confdir" ]] ; then conffile="$confdir/options" distfile="$confdir/distributions" elif [[ -n "${REPREPRO_CONFIG_DIR:+set}" ]] ; then conffile="$REPREPRO_CONFIG_DIR/options" distfile="$REPREPRO_CONFIG_DIR/distributions" else conffile="+b/conf/options" distfile="+b/conf/distributions" fi confbasedir="${basedir:-${REPREPRO_BASE_DIR:-.}}" if [ x"${conffile#+b/}" != x"${conffile}" ] ; then conffile="$confbasedir/${conffile#+b/}" fi if [ -z "$basedir" ] && [[ -e "$conffile" ]] && grep -q '^basedir ' -- "$conffile" 2>/dev/null ; then confbasedir="$(grep '^basedir ' -- "$conffile" 2>/dev/null | sed -e 's/^basedir *//')" fi if [ -z "$confdir" ] && [[ -e "$conffile" ]] && grep -q '^confdir ' -- "$conffile" 2>/dev/null ; then distfile="$(grep '^confdir ' -- "$conffile" 2>/dev/null | sed -e 's/^confdir *//')/distributions" fi if [ x"${distfile#+b/}" != x"${distfile}" ] ; then distfile="$confbasedir/${distfile#+b/}" fi if [[ -d "$distfile" ]] ; then codenames="$(awk -- '/^[Cc][Oo][Dd][Ee][Nn][Aa][Mm][Ee]: / {$1="";print}' "$distfile"/*.conf)" architectures="$(awk -- '/^[Aa][Rr][Cc][Hh][Ii][Tt][Ee][Cc][Tt][Uu][Rr][Ee][Ss]: / {$1="";print}' "$distfile"/*.conf)" components="$(awk -- '/^[Cc][Oo][Mm][Pp][Oo][Nn][Ee][Nn][Tt][Ss]: / {$1="";print}' "$distfile"/*.conf)" elif [[ -e "$distfile" ]] ; then codenames="$(awk -- '/^[Cc][Oo][Dd][Ee][Nn][Aa][Mm][Ee]: / {$1="";print}' "$distfile")" architectures="$(awk -- '/^[Aa][Rr][Cc][Hh][Ii][Tt][Ee][Cc][Tt][Uu][Rr][Ee][Ss]: / {$1="";print}' "$distfile")" components="$(awk -- '/^[Cc][Oo][Mm][Pp][Oo][Nn][Ee][Nn][Tt][Ss]: / {$1="";print}' "$distfile")" else codenames="experimental sid whatever-you-defined" architectures="source i386 abacus whatever-you-defined" components="main contrib non-free whatever-you-defined" fi } function parse_config_for_distdir() { local conffile if [[ -n "$confdir" ]] ; then conffile="$confdir/options" elif [[ -n "${REPREPRO_CONFIG_DIR:+set}" ]] ; then conffile="$REPREPRO_CONFIG_DIR/options" else conffile="+b/conf/options" fi if [ x"${conffile#+b/}" != x"${conffile}" ] ; then conffile="${basedir:-${REPREPRO_BASE_DIR:-.}}/${conffile#+b/}" fi if [ -z "$basedir" ] && [[ -e "$conffile" ]] ; then if grep -q '^basedir ' -- "$conffile" 2>/dev/null ; then basedir="$(grep '^basedir ' -- "$conffile" 2>/dev/null | sed -e 's/^basedir *//')" fi fi if [ -z "$outdir" ] && [[ -e "$conffile" ]] ; then if grep -q '^outdir ' -- "$conffile" 2>/dev/null ; then outdir="$(grep '^outdir ' -- "$conffile" 2>/dev/null | sed -e 's/^outdir *//')" fi fi if [ -z "$distdir" ] && [[ -e "$conffile" ]] ; then if grep -q '^distdir ' -- "$conffile" 2>/dev/null ; then distdir="$(grep '^distdir ' -- "$conffile" 2>/dev/null | sed -e 's/^distdir *//')" fi fi if [ -z "$basedir" ] ; then basedir="${REPREPRO_BASE_DIR:-.}" fi if [ -z "$outdir" ] ; then outdir="${REPREPRO_OUT_DIR:-$basedir}" fi if [ x"${outdir#+b/}" != x"${outdir}" ] ; then outdir="$basedir/${outdir#+b/}" fi if [ -z "$distdir" ] ; then distdir="${REPREPRO_DIST_DIR:-$outdir/dists}" fi if [ x"${distdir#+o/}" != x"${distdir}" ] ; then distdir="$outdir/${distdir#+o/}" elif [ x"${distdir#+b/}" != x"${distdir}" ] ; then distdir="$basedir/${distdir#+b/}" fi } function parse_incoming() { local conffile incomingfile if [[ -n "$confdir" ]] ; then conffile="$confdir/options" incomingfile="$confdir/incoming" elif [[ -n "${REPREPRO_CONFIG_DIR:+set}" ]] ; then conffile="$REPREPRO_CONFIG_DIR/options" incomingfile="$REPREPRO_CONFIG_DIR/incoming" else conffile="+b/conf/options" incomingfile="+b/conf/incoming" fi confbasedir="${basedir:-${REPREPRO_BASE_DIR:-.}}" if [ x"${conffile#+b/}" != x"${conffile}" ] ; then conffile="$confbasedir/${conffile#+b/}" fi if [ -z "$basedir" ] && [[ -e "$conffile" ]] && grep -q '^basedir ' -- "$conffile" 2>/dev/null ; then confbasedir="$(grep '^basedir ' -- "$conffile" 2>/dev/null | sed -e 's/^basedir *//')" fi if [ -z "$confdir" ] && [[ -e "$conffile" ]] && grep -q '^confdir ' -- "$conffile" 2>/dev/null ; then incomingfile="$(grep '^confdir ' -- "$conffile" 2>/dev/null | sed -e 's/^confdir //')/incoming" fi if [ x"${incomingfile#+b/}" != x"${incomingfile}" ] ; then incomingfile="$confbasedir/${incomingfile#+b/}" fi if [[ -d "$incomingfile" ]] ; then importrules="$(awk -- '/^[Nn][Aa][Mm][Ee]: / {$1="";print}' "$incomingfile"/*.conf)" elif [[ -e "$incomingfile" ]] ; then importrules="$(awk -- '/^[Nn][Aa][Mm][Ee]: / {$1="";print}' "$incomingfile")" else importrules="rule-name" fi } COMPREPLY=() ignores='ignore flatandnonflat forbiddenchar 8bit emptyfilenamepart\ spaceonlyline malformedchunk unknownfield\ wrongdistribution missingfield brokenold\ undefinedtracking undefinedtarget unusedoption\ brokenversioncmp extension unusedarch surprisingarch\ surprisingbinary wrongsourceversion wrongversion dscinbinnmu\ brokensignatures uploaders missingfile longkeyid\ expiredkey expiredsignature revokedkey oldfile wrongarchitecture' noargoptions='--delete --nodelete --help -h --verbose -v\ --nothingiserror --nolistsdownload --keepunreferencedfiles --keepunusednewfiles\ --keepdirectories --keeptemporaries --keepuneededlists\ --ask-passphrase --nonothingiserror --listsdownload\ --nokeepunreferencedfiles --nokeepdirectories --nokeeptemporaries\ --nokeepuneededlists --nokeepunusednewfiles\ --noask-passphrase --skipold --noskipold --show-percent \ --version --guessgpgtty --noguessgpgtty --verbosedb --silent -s --fast' options='-b -i --basedir --outdir --ignore --unignore --methoddir --distdir --dbdir\ --listdir --confdir --logdir --morguedir \ --section -S --priority -P --component -C\ --architecture -A --type -T --export --waitforlock \ --spacecheck --safetymargin --dbsafetymargin\ --gunzip --bunzip2 --unlzma --unxz --lunzip --gnupghome --list-format --list-skip --list-max\ --outhook --endhook' i=1 prev="" cmd="XYZnoneyetXYZ" while [[ $i -lt $COMP_CWORD ]] ; do cur=${COMP_WORDS[i]} prev="" case "$cur" in --basedir=*) basedir="${cur#--basedir=}" i=$((i+1)) ;; --outdir=*) outdir="${cur#--basedir=}" i=$((i+1)) ;; --distdir=*) distdir="${cur#--basedir=}" i=$((i+1)) ;; --confdir=*) confdir="${cur#--confdir=}" i=$((i+1)) ;; --*=*) i=$((i+1)) ;; -b|--basedir) prev="$cur" basedir="${COMP_WORDS[i+1]}" i=$((i+2)) ;; --outdir) prev="$cur" outdir="${COMP_WORDS[i+1]}" i=$((i+2)) ;; --distdir) prev="$cur" distdir="${COMP_WORDS[i+1]}" i=$((i+2)) ;; --confdir) prev="$cur" confdir="${COMP_WORDS[i+1]}" i=$((i+2)) ;; -i|--ignore|--unignore|--methoddir|--distdir|--dbdir|--listdir|--section|-S|--priority|-P|--component|-C|--architecture|-A|--type|-T|--export|--waitforlock|--spacecheck|--checkspace|--safetymargin|--dbsafetymargin|--logdir|--gunzip|--bunzip2|--unlzma|--unxz|--lunzip|--gnupghome|--morguedir) prev="$cur" i=$((i+2)) ;; --*|-*) i=$((i+1)) ;; *) cmd="$cur" i=$((i+1)) break ;; esac done cur=${COMP_WORDS[COMP_CWORD]} if [[ $i -gt $COMP_CWORD && -n "$prev" ]]; then case "$prev" in -b|--basedir|--outdir|--methoddir|--distdir|--dbdir|--listdir|--confdir) COMPREPLY=( $( compgen -d -- $cur ) ) return 0 ;; -T|--type) COMPREPLY=( $( compgen -W "dsc deb udeb" -- $cur ) ) return 0 ;; -i|--ignore|--unignore) COMPREPLY=( $( compgen -W "$ignores" -- $cur ) ) return 0 ;; -P|--priority) COMPREPLY=( $( compgen -W "required important standard optional extra" -- $cur ) ) return 0 ;; -S|--section) COMPREPLY=( $( compgen -W "admin base comm contrib devel doc editors electronics embedded games gnome graphics hamradio interpreters kde libs libdevel mail math misc net news non-free oldlibs otherosfs perl python science shells sound tex text utils web x11 contrib/admin contrib/base contrib/comm contrib/contrib contrib/devel contrib/doc contrib/editors contrib/electronics contrib/embedded contrib/games contrib/gnome contrib/graphics contrib/hamradio contrib/interpreters contrib/kde contrib/libs contrib/libdevel contrib/mail contrib/math contrib/misc contrib/net contrib/news contrib/non-free contrib/oldlibs contrib/otherosfs contrib/perl contrib/python contrib/science contrib/shells contrib/sound contrib/tex contrib/text contrib/utils contrib/web contrib/x11 non-free/admin non-free/base non-free/comm non-free/contrib non-free/devel non-free/doc non-free/editors non-free/electronics non-free/embedded non-free/games non-free/gnome non-free/graphics non-free/hamradio non-free/interpreters non-free/kde non-free/libs non-free/libdevel non-free/mail non-free/math non-free/misc non-free/net non-free/news non-free/non-free non-free/oldlibs non-free/otherosfs non-free/perl non-free/python non-free/science non-free/shells non-free/sound non-free/tex non-free/text non-free/utils non-free/web non-free/x11" -- $cur ) ) return 0 ;; -A|--architecture) parse_config COMPREPLY=( $( compgen -W "$architectures" -- $cur ) ) return 0 ;; -C|--component) parse_config COMPREPLY=( $( compgen -W "$components" -- $cur ) ) return 0 ;; --export) COMPREPLY=( $( compgen -W "silent-never never changed lookedat force" -- $cur ) ) return 0 ;; --waitforlock) COMPREPLY=( $( compgen -W "0 60 3600 86400" -- $cur ) ) return 0 ;; --spacecheck) COMPREPLY=( $( compgen -W "none full" -- $cur ) ) return 0 ;; --safetymargin) COMPREPLY=( $( compgen -W "0 1048576" -- $cur ) ) return 0 ;; --dbsafetymargin) COMPREPLY=( $( compgen -W "0 104857600" -- $cur ) ) return 0 ;; esac fi if [[ "XYZnoneyetXYZ" = "$cmd" ]] ; then commands='build-needing\ check\ checkpool\ checkpull\ checkupdate\ cleanlists\ clearvanished\ collectnewchecksums\ copy\ copyfilter\ copymatched\ copysrc\ createsymlinks\ deleteunreferenced\ deleteifunreferenced\ dumpreferences\ dumptracks\ dumppull\ dumpunreferenced\ dumpupdate\ export\ forcerepairdescriptions\ flood\ generatefilelists\ gensnapshot\ unreferencesnapshot\ include\ includedeb\ includedsc\ includeudeb\ list\ listfilter\ listmatched\ ls\ lsbycomponent\ move\ movefilter\ movematched\ movesrc\ predelete\ processincoming\ pull\ remove\ removealltracks\ removefilter\ removematched\ removesrc\ removesrcs\ removetrack\ reoverride\ repairdescriptions\ reportcruft\ rereference\ rerunnotifiers\ restore\ restorefilter\ restorematched\ restoresrc\ retrack\ sourcemissing\ tidytracks\ translatefilelists\ translatelegacychecksums\ unusedsources\ update' hiddencommands='__d\ __dumpuncompressors __extractcontrol\ __extractfilelist\ __extractsourcesection\ __uncompress\ _addchecksums\ _addpackage\ _addreference\ _addreferences\ _detect\ _dumpcontents\ _fakeemptyfilelist\ _forget\ _listchecksums\ _listcodenames\ _listconfidentifiers\ _listdbidentifiers\ _listmd5sums\ _removereference\ _removereferences\ _versioncompare' if [[ "$cur" == -* ]]; then case "$cur" in --ignore=*) COMPREPLY=( $( compgen -W "$ignores" -- ${cur#--ignore=} ) ) ;; --unignore=*) COMPREPLY=( $( compgen -W "$ignores" -- ${cur#--unignore=} ) ) ;; --component=*) parse_config COMPREPLY=( $( compgen -W "$components" -- {cur#--component=} ) ) ;; --architectures=*) parse_config COMPREPLY=( $( compgen -W "$architectures" -- {cur#--architectures=} ) ) ;; *) COMPREPLY=( $( compgen -W "$options $noargoptions" -- $cur ) ) ;; esac elif [[ "$cur" == _* ]]; then COMPREPLY=( $( compgen -W "$hiddencommands" -- $cur ) ) else COMPREPLY=( $( compgen -W "$commands" -- $cur ) ) fi return 0 fi case "$cmd" in remove|list|listfilter|removefilter|removetrack|listmatched|removematched|removesrc|removesrcs) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # these later could also look for stuff, but # that might become a bit slow ;; export|update|checkupdate|pull|checkpull|rereference|retrack|removealltracks|tidytracks|dumptracks|check|repairdescriptions|forcerepairdescriptions|reoverride|rerunnotifiers|dumppull|dumpupdate|unusedsources|sourcemissing|reportcruft) # all arguments are codenames parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 ;; processincoming) # arguments are rule-name from conf/incoming parse_config parse_incoming if [[ $i -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -W "$importrules" -- $cur ) ) return 0 fi ;; collectnewchecksums|cleanlists|_listcodenames) return 0 ;; checkpool) # first argument can be fast if [[ $i -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -W "fast" -- $cur ) ) return 0 fi return 0 ;; flood) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then an architecture might follow if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$architectures" -- $cur ) ) return 0 fi # then nothing else return 0 ;; build-needing) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then an architecture if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$architectures" -- $cur ) ) return 0 fi # then a glob if [[ $(( $i + 2 )) -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -W "$cur'\*'" -- $cur ) ) return 0 fi return 0 ;; __uncompress) # first argument is method if [[ $i -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -W ".gz .bz2 .lzma .xz .lz" -- $cur ) ) return 0 fi if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -f -- $cur ) ) return 0 fi if [[ $(( $i + 2 )) -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -f -- $cur ) ) return 0 fi return 0 ;; __extractsourcesection) if [[ $i -eq $COMP_CWORD ]] ; then _filedir dsc fi return 0 ;; includedeb) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then one .deb file follows if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then _filedir deb fi return 0 ;; includedsc) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then one .dsc file follows if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then _filedir dsc fi return 0 ;; include) # first argument is the codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then one .changes file follows if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then _filedir changes fi return 0 ;; gensnapshot|unreferencesnapshot) # first argument is a codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # then the name of a snapshot, add a suggestion if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then COMPREPLY=( $( compgen -W "$(date +%Y/%m/%d)" -- $cur ) ) return 0 fi return 0; ;; copy|copysrc|copyfilter|copymatched|move|movesrc|movefilter|movematched) # first argument is a codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # second argument is a codename if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # here we could look for package names existing in # that distribution, but that would be slow... ;; restore|restoresrc|restorefilter|restorematched) # first argument is a codename if [[ $i -eq $COMP_CWORD ]] ; then parse_config COMPREPLY=( $( compgen -W "$codenames" -- $cur ) ) return 0 fi # second argument is snapshot of that name if [[ $(( $i + 1 )) -eq $COMP_CWORD ]] ; then parse_config_for_distdir snapshots="$( ls "$distdir/${COMP_WORDS[i]}/snapshots" )" COMPREPLY=( $( compgen -W "$snapshots" -- $cur ) ) return 0 fi # here we could look for package names existing in # that distribution, but that would be slow... ;; __dumpuncompressors|translatelageacychecksums|deleteunreferenced) # no arguments return 0 ;; deleteifunreferenced) # less useful than the output of dumpunreferenced, # but this way it should be massively faster: parse_config_for_distdir COMPREPLY=( $(cd "$outdir" && compgen -o filenames -f -- $cur) ) return 0 ;; esac COMPREPLY=( $( compgen -f -- $cur ) ) return 0 } # This -o filename has its problems when there are directories named like # commands in you current directory. But it makes adding filenames so much # easier. I wished I knew a way to only active it for those parts that are # filenames. complete -o filenames -F _reprepro reprepro _changestool() { local cur prev commands options noargoptions i j cmd ignores wascreate changesfilename COMPREPLY=() ignores=' notyetimplemented ' noargoptions='--help --create' options='--ignore --searchpath' wascreate=no i=1 prev="" while [[ $i -lt $COMP_CWORD ]] ; do cur=${COMP_WORDS[i]} prev="" case "$cur" in --*=*) i=$((i+1)) ;; -i|--ignore|--unignore|-s|--searchpath) prev="$cur" i=$((i+2)) ;; --create|-c) i=$((i+1)) wascreate=yes ;; --*|-*) i=$((i+1)) ;; *) break ;; esac done cur=${COMP_WORDS[COMP_CWORD]} if [[ $i -gt $COMP_CWORD && -n "$prev" ]]; then case "$prev" in -i|--ignore|--unignore) COMPREPLY=( $( compgen -W "$ignores" -- $cur ) ) return 0 ;; -s|--searchpath) COMPREPLY=( $( compgen -d -- $cur ) ) return 0 ;; esac fi if [[ $i -ge $COMP_CWORD ]] ; then # No changes filename yet specified: commands='addrawfile adddsc adddeb add includeallsources setdistribution updatechecksums verify' if [[ "$cur" == -* ]]; then case "$cur" in *) COMPREPLY=( $( compgen -W "$options $noargoptions" -- $cur ) ) ;; esac return 0 fi if [ "$wascreate" = "yes" ] ; then _filedir else _filedir changes fi return 0 fi changesfilename=${COMP_WORDS[i]} i=$((i+1)) if [[ $i -ge $COMP_CWORD ]] ; then # No command yet specified: commands='addrawfile adddsc adddeb add includeallsources setdistribution updatechecksums verify' # todo: restrict to add commands when --create and file not yet existing? COMPREPLY=( $( compgen -W "$commands" -- $cur ) ) return 0 fi cmd=${COMP_WORDS[i]} case "$cmd" in # with searchpath it should also list the files available there, # but I know no easy way to get that done... addrawfile) _filedir return 0 ;; adddsc) _filedir dsc return 0 ;; adddeb) _filedir deb return 0 ;; adddeb) _filedir return 0 ;; includeallsources) prev="$(grep '^ [0-9a-f]\{32\} \+[0-9]\+ \+[a-zA-Z/0-9.:-]\+ \+[a-zA-Z/0-9.:-]\+ \+[^ ]\+\.dsc$' -- "$changesfilename" | sed -e 's/^ [0-9a-f]\+ \+[0-9]\+ \+[^ ]\+ \+[^ ]\+ \+//')" j=0 options=() for i in $prev ; do if [ -f "$i" ] ; then options=(${options[@]:-} $(grep '^ [0-9a-f]\{32\} \+[0-9]\+ \+[^ ]\+$' -- "$i" | sed -e 's/^ [0-9a-f]\+ \+[0-9]\+ \+//') ) elif [ -f "$(dirname $changesfilename)/$i" ] ; then options=(${options[@]:-} $(grep '^ [0-9a-f]\{32\} \+[0-9]\+ \+[^ ]\+$' -- "$(dirname $changesfilename)/$i" | sed -e 's/^ [0-9a-f]\+ \+[0-9]\+ \+//') ) else cmd="missing" fi done COMPREPLY=( $( compgen -W "${options[@]}" -- $cur ) ) # if some .dsc cannot be found or read, offer everything additionally if [ "$cmd" = "missing" ] ; then _filedir fi return 0 ;; setdistribution) COMPREPLY=( $( compgen -W "unstable testing stable sarge etch lenny sid backports local" -- $cur ) ) return 0 ;; updatechecksums) options="$(grep '^ [0-9a-f]\{32\} \+[0-9]\+ \+[a-zA-Z/0-9.:-]\+ \+[a-zA-Z/0-9.:-]\+ \+[^ ]\+$' -- "$changesfilename" | sed -e 's/^ [0-9a-f]\+ \+[0-9]\+ \+[^ ]\+ \+[^ ]\+ \+//')" if [ -n "$options" ] ; then COMPREPLY=( $( compgen -W "$options" -- $cur ) ) else _filedir fi return 0 ;; verify) return 0 ;; esac COMPREPLY=( $( compgen -f -- $cur ) ) return 0 } # same problem as above with -o filenames, # but I guess still better than without... complete -o filenames -F _changestool changestool