Follow us on Twitter or via RSS feeds with tweets or complete announcement texts or excerpts
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date: Sat, 2 Jun 2012 02:01:21 +0200
From: Frank Dittrich <frank_dittrich@...mail.com>
To: john-users@...ts.openwall.com
Subject: Re: bash completion for john and unique

On 05/21/2012 10:24 AM, Frank Dittrich wrote:
> I created a bash completion script for John the Ripper which supports
> bash completion for john (official releases and jumbo versions) 

Unfortunately, nobody replied to that mail.
This either means, nobody is interested in bash completion for john, my
last mail was too confusing, or everybody was happy with my script and
didn't find any problems.

Anyway, meanwhile a lot has been changed.

Attached to this mail is the newest version of the script.
(This version is not yet available in magnum's git repository, but I
hope this will not take very long - unless magnum finds bugs in my code.)

The bash completion script now not only supports completion for
--option=val, but also for abbreviated forms --opt=val or -opt=val as
well as options with a colon instead of an equal sign as a separator:
--option:val, -opt:val, and so on.

The location of the script will also change when the next jumbo is released.

My previous mail in this thread describes how to enable bash completion,
and how to adjust completion according to your preferences:

http://openwall.com/lists/john-users/2012/05/21/1

Please test the bash completion, so that I can fix bugs prior to the
next jumbo release.


Frank

# bash completion for john and unique commands (John the Ripper)
#
# This software is Copyright © 2012 Frank Dittrich
# and hereby released to the general public under the following terms:
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted.
#
# Minor improvements suggested by Aleksey Cherepanov have been
# incorporated.
#
#
# This file needs to be copied into the /etc/bash_completion.d/.
# To make the new completion rules work, you need to logout and login,
# or source /etc/bash_completion instead.
#
# Alternatively, just add a line
# . <path_to_john's_source_directory>/john.bash_completion
# to your ~/.bashrc and logout/login.
#
# To use the same completion rules not just for john, but for 
# differently named binaries (say john-omp, john-sse2i, john-avx,
# john-cuda, john-gpu, ...),
# just use this command to get the current completion rule settings:
#       complete -p john
#
# If the output is
#       complete -F _john john
# you can use this command to activate the same completion rules
# for john-omp:
#       complete -F _john john-omp
#
# To use these completion rules permanently, you might add
#       complete -F _john john-omp
# to your ~/.bashrc file.
#
#
# The code is still ugly, many things can probably be done more efficiently.
# Currently, grep, tr, and sed are the only external commands used.
# Trying to build a perfect completion script will be hard.
#
# If possible, I'd like to avoid the need to maintain this script whenever
# john gets a new option.
#
# john can either be globally installed (e.g. in /usr/bin/john),
# or it can be installed locally somewhere in a user's home directory.
# It can be an official version, or a community encanced (jumbo) version,
# with a variety of patches.
#
# FIXME: Is using __expand_tilde_by_ref OK?
#
# FIXME: For some reason completion for --option= only works 
#	 if the cursor is at the end of the command, 
#	 i.e. [[ ${COMP_POINT} -eq ${#COMP_LINE} ]]
#	 not if some words follow the one to be completed...
#	 If ${cur#*=} is not empty, completion works even in the middle
#	 of the command line
#	 This is annoying if I want to complete --rules= in
#        ./john --rules= --config=test.conf
#
# FIXME: If there is a word -- preceding the current word 
#        which is to be completed, it cannot be an option, so file names
#        should be used for completion.
#
# FIXME: Should completion for --make-charset really list existing .chr files?
#
# FIXME: Should I generally use LC_ALL=C, not just in a few places?
#	 (This could also be a little bit faster.)
#
# TODO:
#       --wordlist=~user/filename or --wordlist=~/dir/file doesn't work,
#         but pressing [tab] expands this to something useful
#         Where to fix this? In john? Some bash config option?
#
#       --external should not use all names of [List.External:..-.] sections, but
#         just sections without a generate() function, if --wordlist, --incremental or --single
#         is present on the command line; and just those with a generate() function,
#         if none of these options is used - WHAT IF the user adds a --wordlist option later?
#
#	Should expanding an abbreviated option to its long form also be done by john itself
#	(requires new john option)?

# different implementations for completion logic for these options:
# --rules --single --incremental --restore --status
# for __john_completion=[2|any other value]
#
# john
## on my system, have() is a dummy function which always return "yes", so get rid of calling it... 
## have grep && have sed && have tr 
_john()
{
	local first cur options valopts compreplya compreplyb encodings formats subformats list hidden dir cmd i ver ver1 ver2 ver3 prev words
	COMPREPLY=()

	if [[ "${COMP_WORDBREAKS}" == *:* ]] ; then
		_get_comp_words_by_ref -n := cur prev words
	else
		_get_comp_words_by_ref -n = cur prev words
		# If the colon is not part of COMP_WORDBREAKS, e.g., due to
		# including this line into your ~/.bashrc, as mentioned in
		# /etc/bash_completion ...
		# 	export COMP_WORDBREAKS="${COMP_WORDBREAKS//:}"
		# just replace : with = in -opt:val
		if [[ "${cur}" == -*:* ]] ; then
			cur="${cur//:/=}"
			COMPREPLY=( $(compgen -W "${cur}" -- ${cur}) )
			compopt -o nospace
			return 0
		fi
	fi

#	We need to make sure we run the correct program, not some other program 
#	called john which is located somewhere in $PATH
	first="${COMP_WORDS[0]}"
#	Most options are listed at the begin of the line, but the line with the --pipe option
#	does have trailing spaces, and --stdin is mentioned after --wordlist=FILE.
#
#	All options (the '=' will be removed for options with an optional value)
	options=""
# FIXME: How do I suppress the error message if someone tries to be clever: cd run; ./john --[tab] ???
	options="`${first} 2>/dev/null|sed -n '{ s#^ *\(--[a-z-]*=\?\(LIST\)\?\).*$#\1# }; /^--/ p'` --stdin"
	if [[ "_${options}" == "_ --stdin" ]] ; then
		_filedir_xspec 2> /dev/null
		return 0
	fi

#	Just those options that can be used together with a value, even if that value is optional:
	valopts=`${first} 2>/dev/null|grep '^ *--[a-z\[-]*='|grep -v '^ *--subformat='|sed 's#^ *\([a-z=-]*\).*$#\1#'`
#	This is used to decide whether or not the completion should add a trailing space.
#	(That means, for a jumbo build, --rules doesn't get a trailing space, but for the john version
#	distributed by fedora16, --rules does get a trailing space during completion.
#	The same applies for --show and single)

#	now add the "hidden options" (not mentioned in the usage output, but in doc/OPTIONS and 
#       with --list=hidden-options
#	Currently, all hidden options do have mandatory values (--option=value), this makes
#       addition of these easier
	hidden=""
	hidden=`${first} --list=hidden-options 2>/dev/null|sed 's#^\(--[a-z-]*=\?\).*$#\1#'`

	case "${cur}" in
		-?(-)fo?(r|rm|rma|rmat)+(=|:)dynamic*)
			if [[ "${options}" == *--subformat* ]] ; then
				 subformats=`${first} --subformat=LIST|sed 's#^\(User\)\?Format = \(dynamic_[0-9]*\).*$#\2#'`
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "${subformats}" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)fo?(r|rm|rma|rmat)+(=|:)dy?(n|na|nam|nami))
			if [[ "${options}" == *--subformat* ]] ; then
				if [[ "${cur#*f}" == o[=:]* || "${cur#*f}" == or[=:]* ]] ; then
					if [[ `echo "${valopts}"|grep -c "^-*${cur%[=:]*}"` -ne 1 ]] ; then
						return 0
					fi
				fi
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "dynamic" -- ${cur}) )
				compopt -o nospace
			fi
			return 0
			;;
		-?(-)fo?(r|rm|rma|rmat)+(=|:)*)
			if [[ "${cur#*f}" == o[=:]* || "${cur#*f}" == or[=:]* ]] ; then
				if [[ `echo "${valopts}"|grep -c "^-*${cur%[=:]*}"` -ne 1 ]] ; then
					return 0
				fi
			fi
			cur=${cur#*[=:]}
			formats=`${first} |sed -n '/^--format/,$ { s#^--format=[ A-Za-z]*:##; /^--/ b; s#^ *##; s#\<dynamic_n\>#dynamic#; s#[/ ]#\n#g; p }'`
			COMPREPLY=( $(compgen -W "${formats}" -- ${cur}) )
			return 0
			;;

		--restore|--status)
			if [[ "_${__john_completion}" == "_2" ]] ; then
				COMPREPLY=( $(compgen -W "${cur}=" -- ${cur}) )
				compopt -o nospace
			else
				prev="${cur}"
				cur=""
				_filedir "rec"
				for (( i=0; i < ${#COMPREPLY[@... i++)); do
					COMPREPLY[$i]="${prev}=${COMPREPLY[$i]%*.rec}"
				done
				COMPREPLY[${#COMPREPLY[@...="${prev}"
			fi
			return 0
			;;
		-?(-)re?(s|st|sto|stor|store)+(=|:)*|-?(-)sta?(t|tu|tus)+(=|:)*)
			if [[ "${cur}" == -re[=:]* || "${cur}" == --re[=:]* ]] ; then
				if [[ `echo "${valopts}"|grep -c "^--re"` -ne 1 ]] ; then
					return 0
				fi
			fi
# If there is no .rec file in the current directory, the old completion logic will show all files:
##echo _`for f in *.rec; do echo ${f%.rec};done`_
			cur=${cur#*[=:]}
# cd $JOHN/ or Private home for system-wide builds, if ./john --list=build-info works?
# NO, this would be wrong!
# .rec files are stored in the current directory (or a subdirectory if the session name contains a slash)

			__expand_tilde_by_ref cur 2>/dev/null
			_filedir "rec"
			for (( i=0; i < ${#COMPREPLY[@... i++)); do
				# Do I have to add the trailing / for directories? Apparently not!
				COMPREPLY[$i]="${COMPREPLY[$i]%*.rec}"
			done
			return 0
			;;
		-?(-)w?(o|or|ord|ordl|ordli|ordlis|ordlist)+(=|:)*)
			cur=${cur#*[=:]}
			 __expand_tilde_by_ref cur 2>/dev/null
			_filedir
			return 0
			;;
 		--rules|--single)
			if [[ "${valopts}" == *${cur}* ]] ; then
				if [[ "_${__john_completion}" == "_2" ]] ; then
					COMPREPLY=( $(compgen -W "${cur}=" -- ${cur}) )
					compopt -o nospace
				else
					cmd=`echo ${COMP_LINE}|sed "s# ${cur}# --list=rules #"`
					list=`${cmd} 2>/dev/null`
					if [[ $? -ne 0 ]] ; then
						list=`${first} --list=rules 2>/dev/null`
					fi
					if [[ $? -ne 0 ]] ; then
						list="single wordlist NT"
					fi
					list=`echo "${list}"|sed 's# #\n#g'|sed "s#^\(.\)#${cur}=\1#"`
					list="${list} ${cur}"
					COMPREPLY=( $(compgen -W "${list}" -- ${cur}) )
				fi
			else
				COMPREPLY=( $(compgen -W "${cur}" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)ru?(l|le|les)+(=|:)*|-?(-)si?(n|ng|ngl|ngle)+(=|:)*)
			# let's assume every john version which supports --single= 
			# also supports --rules=, and vice versa
			if [[ "${valopts}" == *--rules* ]] ; then
				cmd=`echo ${COMP_LINE}|sed "s# ${cur}# --list=rules #"`
				list=`${cmd} 2>/dev/null`
				if [[ $? -ne 0 ]] ; then
					list=`${first} --list=rules 2>/dev/null`
				fi
				if [[ $? -eq 0 ]] ; then
					cur=`echo ${cur#*[=:]}|LC_ALL=C tr A-Z a-z`
					COMPREPLY=( $(compgen -W "${list}" -- ${cur}) )
				else
					cur=${cur#*[=:]}
					COMPREPLY=( $(compgen -W "NT single wordlist" -- ${cur}) )
				fi
			fi
			return 0
			;;
		-?(-)ex?(t|te|ter|tern|terna|ternal)+(=|:)*)
			cmd=`echo ${COMP_LINE}|sed "s# ${cur}# --list=externals #"`
			list=`${cmd} 2>/dev/null`
			if [[ $? -ne 0 ]] ; then
				list=`${first} --list=externals 2>/dev/null`
			fi
			if [[ $? -ne 0 ]] ; then
				list="Filter_Alpha Filter_Digits Filter_Alnum Filter_LanMan LanMan Double Parallel Strip Keyboard"
				ver=`${first} 2>/dev/null|sed -n '/^John the Ripper password cracker, ver/ s#^John the Ripper password cracker, ver[a-z :]*\([0-9.]*\).*$#\1#p'`
				ver1=`echo $ver|sed 's#^\([0-9]*\).*$#\1#'`
				ver2=`echo $ver|sed 's#^[0-9]*.\([0-9]*\).*$#\1#'`
				ver3=`echo $ver|sed 's#^[0-9]*.[0-9]*.\([0-9]*\).*$#\1#'`
				if [[ "_${ver3}" == "_" ]] ; then
					ver3=0
				fi
				if [[ $ver1 -eq 1 && $ver2 -eq 7 ]] ; then
					if [[ $ver3 -ge 3 ]] ; then
						list="${list} DumbForce KnownForce"
					fi
					if [[ $ver3 -ge 7 ]] ; then
						list="${list} DateTime Repeats Subsets AtLeast1-Simple AtLeast1-Generic Policy"
					fi
					if [[ $ver3 -ge 8 ]] ; then
						list="${list} AppendLuhn"
					fi
					if [[ $ver3 -ge 9 ]] ; then
						list="${list} AutoAbort AutoStatus"
					fi
				else
					if [[ $ver1 -gt 1 || $ver1 -eq 1 && ver2 -gt 7 ]] ; then
						list="${list} DumbForce KnownForce DateTime Repeats Subsets AtLeast1-Simple AtLeast1-Generic Policy AppendLuhn AutoAbort AutoStatus"
					fi
				fi
				cur=${cur#*[=:]}
			else
				cur=`echo ${cur#*[=:]}|LC_ALL=C tr A-Z a-z`
			fi
			COMPREPLY=( $(compgen -W "${list}" -- ${cur}) )
			return 0
			;;
		--incremental)
			if [[ "_${__john_completion}" == "_2" ]] ; then
				COMPREPLY=( $(compgen -W "${cur}=" -- ${cur}) )
				compopt -o nospace
			else
				cmd=`echo ${COMP_LINE}|sed "s# ${cur}# --list=inc-modes #"`
				list=`${cmd} 2>/dev/null`
				if [[ $? -ne 0 ]] ; then
					list=`${first} --list=inc-modes 2>/dev/null`
				fi
				if [[ $? -ne 0 ]] ; then
					list="All Alpha Digits Alnum LanMan"
				fi
				list=`echo "${list}"|sed 's# #\n#g'|sed "s#^\(.\)#${cur}=\1#"`
				list="${list} ${cur}"
				COMPREPLY=( $(compgen -W "${list}" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)i?(n|nc|ncr|ncre|ncrem|ncreme|ncremen|ncrement|ncrementa|ncremental)+(=|:)*)
			cmd=`echo ${COMP_LINE}|sed "s# ${cur}# --list=inc-modes #"`
			list=`${cmd} 2>/dev/null`
			if [[ $? -ne 0 ]] ; then
				list=`${first} --list=inc-modes 2>/dev/null`
			fi
			if [[ $? -eq 0 ]] ; then
				cur=`echo ${cur#*[=:]}|LC_ALL=C tr A-Z a-z`
				COMPREPLY=( $(compgen -W "${list}" -- ${cur}) )
			else
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "All Alpha Digits Alnum LanMan" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)mak?(e|e-|e-c|e-ch|e-cha|e-char|e-chars|e-charse|e-charset)+(=|:)*)
			cur=${cur#*[=:]}
			#redirect stderr just in case __expand_tilde_by_ref
			#doesn't exist everywhere
			#(I'm a bit worried because of the __ at the begin.
			#May be this function isn't part of an "official" API.)
			__expand_tilde_by_ref cur 2>/dev/null
# FIXME:		should I just use directories for completion, not files, 
# FIXME:		to make overwriting existing files harder?
			_filedir "chr"
			return 0
			;;
		--stdout)
			COMPREPLY=( $(compgen -W "--stdout --stdout=LENGTH" -- ${cur}) )
			return 0
			;;
		--markov)
			if [[ "${valopts}" == *${cur}* ]] ; then
				COMPREPLY=( $(compgen -W "--markov --markov=LEVEL[:START[:END[:LENGTH]]]" -- ${cur}) )
			fi
			return 0
			;;
		--test)
			if [[ "${valopts}" == *${cur}* ]] ; then
				COMPREPLY=( $(compgen -W "--test --test=SECONDS" -- ${cur}) )
			else
				COMPREPLY=( $(compgen -W "${cur}" -- ${cur}) )
			fi
			return 0
			;;
		--show)
			if [[ "${valopts}" == *${cur}* ]] ; then
				COMPREPLY=( $(compgen -W "--show --show=LEFT" -- ${cur}) )
			else
				COMPREPLY=( $(compgen -W "--show" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)sho?(w)+(=|:)l*)
			if [[ "${valopts}" == *--show* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "left" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)sho?(w)+(=|:)*)
			if [[ "${valopts}" == *--show* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "LEFT" -- ${cur}) )
			fi
			return 0
			;;
		--users=?(-)+(L|U)*|--groups=+(-|G)*|--shells=+(-|S)*|--salts=+(-|C)*)
			return 0
			;;
		--users=?(-))
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "LOGIN,... UID,... -LOGIN,... -UID,..." -- ${cur}) )
			return 0
			;;
		--groups=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "GID,... -GID,..." -- ${cur}) )
			return 0
			;;
		--shells=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "SHELL,... -SHELL,..." -- ${cur}) )
			return 0
			;;
		--salts=*)
			cur=${cur#*=}
			COMPREPLY=( $(compgen -W "COUNT -COUNT" -- ${cur}) )
			return 0
			;;
		-?(-)en?(c|co|cod|codi|codin|coding)+(=|:)*)
			if [[ "${valopts}" == *--encoding=* ]] ; then
				# --encoding=LIST writes to stderr
				encodings=`${first} --encoding=LIST 2>&1|grep -v 'Supported encodings'|sed 's#[,)]##g'|sed 's#(or ##g'`
			cur=${cur#*[=:]}
				if [[ ${COMP_CWORD} -eq 2 || ${COMP_CWORD} -eq 3 && "_${cur}" != "_" ]] ; then
					encodings="${encodings} LIST"
					# make sure LIST will be the first option:
					LC_ALL=C
				fi
				COMPREPLY=( $(compgen -W "${encodings}" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)po?(t)+(=|:)*)
			if  [[ "${valopts}" == *--pot=* ]] ; then
				# if --pot= is used, john always looks for the file $PWD
				# (tested with system-wide and local build of john)
				cur=${cur#*[=:]}
				#redirect stderr just in case __expand_tilde_by_ref
				#doesn't exist everywhere
				#(I'm a bit worried because of the __ at the begin.
				#May be this function isn't part of an "official" API.)
				__expand_tilde_by_ref cur 2>/dev/null
				_filedir "pot"
			fi
			return 0
			;;
		-?(-)co?(n|nf|nfi|nfig)+(=|:)*)
			if [[ "${valopts}" == *--config=* ]] ; then
				# if --config= is used, john always looks for files in $PWD
				# (tested for system-wide and local builds)
				cur=${cur#*[=:]}
				__expand_tilde_by_ref cur 2>/dev/null
				_filedir '@...nf|ini)'
			fi
			return 0
			;;
		-?(-)sav?(e|e-|e-m|e-me|e-mem|e-memo|e-memor|e-memory)+(=|:)*)
			cur=${cur#*[=:]}
			COMPREPLY=( $(compgen -W "1 2 3" -- ${cur}) )
			return 0
			;;
		-?(-)reg?(e|en|en-|en-l|en-lo|en-los|en-lost|en-lost-|en-lost-s|en-lost-sa|en-lost-sal|en-lost-salt|en-lost-salts)+(=|:)*)
			if [[ "${valopts}" == *--regen-lost-salts=* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "1 2 3 4 5" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)su?(b|bf|bfo|bfor|bform|bforma|bformat)+(=|:)l*)
			if [[ "${options}" == *--subformat=* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "list" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)su?(b|bf|bfo|bfor|bform|bforma|bformat)+(=|:)*)
			if [[ "${options}" == *--subformat=* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "LIST" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)pla?(t|tf|tfo|tfor|tform)+(=|:)+(L|l)*|-?(-)dev?(i|ic|ice)+(=|:)+(L|l)*)
			# CUDA doesn't allow --device=LIST
			# workaround: check if --platform= is allowed
			if [[ "${valopts}" == *--platform=* ]] ; then
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "LIST list" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)platform+(=|:)|-?(-)device+(=|:))
			# --device=LIST isn't supported for CUDA, but for CUDA
			# --platform= is not a valid option
			if [[ "${valopts}" == *--platform=* ]] ; then
				# Calling john --platform=LIST just to find possible completions
				# will take too long
				cur=${cur#*[=:]}
				COMPREPLY=( $(compgen -W "LIST N" -- ${cur}) )
			fi
			return 0
			;;
		-?(-)l?(i|is|ist)+(=|:)*)
			if [[ "${hidden}" == *--list=* ]] ; then
				cur=${cur#*[=:]}
				# the --list=? output changed, that's why a more complex regex is used
				# to cover all cases
				list=`${first} --list=? 2>/dev/null|sed 's#\(,\)\?\( or\)\?[ ]*[<].*$##; s#,##g'`
				if [[ $? -eq 0 ]] ; then
					# add "?" to the list of possible completions, but don't add any
					# section names like "Options"...
					COMPREPLY=( $(compgen -W "${list} ?" -- ${cur}) )
				fi
			fi
			return 0
			;;
		-*+(=|:))
			return 0;
			;;
		-*)
			compreplya=`compgen -W "${options} ${hidden}" -- ${cur}`
			if [[ "_${compreplya}_" == "__" ]] ; then
				cur="-${cur}"
				compreplya=`compgen -W "${options} ${hidden}" -- ${cur}`
			fi
			compreplyb=`compgen -W "${valopts} ${hidden}" -- ${cur}`
			COMPREPLY=( $(compgen -W "${options} ${hidden}" -- ${cur}) )
			if [[ "_${compreplya}" == "_${compreplyb}" ]] ; then
				compopt -o nospace
			fi
			return 0
			;;
		*)
			_filedir
			return 0
			;;
	esac
} &&
complete -F _john john

# unique
## have grep && have sed &&
_unique()
{
	local first cur usage options valopts compreplya compreplyb
        COMPREPLY=()
        _get_comp_words_by_ref -n = cur

# we need to make sure we run the correct program, not some other program 
# called unique which is located somewhere in $PATH
	first="${COMP_WORDS[0]}"
	usage=`${first}|grep '^Usage:'|sed 's#^Usage:\? \?[^ ]*unique *##'`
	case "_${cur}" in
		_|_${first})
			if [[ "_${usage}" != "_OUTPUT-FILE" ]] ; then
				COMPREPLY=( $(compgen -W "${usage}" -- "") )
			fi
			return 0
			;;
		_-cut=*|_-mem=*)
			return 0
			;;
		_-inp=*|_-ex_file=*|_-ex_file_only=*)
                        cur=${cur#*=}
			__expand_tilde_by_ref cur 2>/dev/null
			_filedir
			return 0
			;;
		_-*)
			if [[ "_${usage}_" != "_OUTPUT-FILE_" ]] ; then
				options=`echo ${usage}|sed 's# #\n#g'|grep '^\[.*\]$'|sed 's#^.\(.*\).$#\1#'|sed 's#=.*$#=#'`
				valopts=`echo "${options}"|grep '='`
				compreplya=`compgen -W "${options}" -- ${cur}`
				compreplyb=`compgen -W "${valopts}" -- ${cur}`
				if [[ "_${compreplya}" == "_${compreplyb}" ]] ; then
					COMPREPLY=( $(compgen -W "${valopts}" -- "${cur}") )
					compopt -o nospace
				else
					COMPREPLY=( $(compgen -W "${options}" -- "${cur}") )
				fi
			fi
			return 0
			;;
		_*)
			return 0
			;;
	esac
} &&
complete -F _unique unique

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux - Powered by OpenVZ