Skip to content

Instantly share code, notes, and snippets.

@aguytech
Last active August 28, 2022 03:55
Show Gist options
  • Save aguytech/5ab9a6a28adaaf664a5d80fa648a4f63 to your computer and use it in GitHub Desktop.
Save aguytech/5ab9a6a28adaaf664a5d80fa648a4f63 to your computer and use it in GitHub Desktop.
[bash-completion] personal bash completions #bash #bashroot #tips

https://opensource.com/article/18/3/creating-bash-completion-script

COMPREPLY

an array variable used to store the completions. The completion mechanism uses this variable to display its contents as completions

COMPREPLY=( $(compgen -W "now tomorrow never" -- ${COMP_WORDS[COMP_CWORD]}) ) # propose given words at each let choose the first completion from given words and repeat it after (replace)
COMPREPLY=( $(compgen -W "now tomorrow never" "${COMP_WORDS[1]}") ) # let choose the first completion from given words and repeat it after (replace)

complete

https://helpmanual.io/man1/bash/

complete [-abcdefgjksuv] [-o comp-option] [-DE] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command]
[-X filterpat] [-P prefix] [-S suffix] name [name ...]
complete -pr [-DE] [name ...]

complete command to register this list for completion

-o comp-option # The comp-option controls several aspects of the compspec's behavior beyond the simple generation of completions. comp-option may be one of:
    bashdefault # Perform the rest of the default bash completions if the compspec generates no matches. 
    default # Use readline's default filename completion if the compspec generates no matches. 
    dirnames #  # Perform directory name completion if the compspec generates no matches. 
    filenames # Tell readline that the compspec generates filenames, so it can perform any filename-specific processing (like adding a slash to directory  names, quoting special characters, or suppressing trailing spaces). Intended to be used with shell functions. 
    noquote # Tell readline not to quote the completed words if they are filenames (quoting filenames is the default). 
    nospace # Tell readline not to append a space (the default) to words completed at the end of the line. 
    plusdirs #  # After any matches defined by the compspec are generated, directory name completion is attempted and any matches are added to the results of the other actions. 

-A action # The action may be one of the following to generate a list of possible completions:
    alias # Alias names. May also be specified as -a. 
    arrayvar # Array variable names. 
    binding # Readline key binding names. 
    builtin # Names of shell builtin commands. May also be specified as -b. 
    command # Command names. May also be specified as -c. 
    directory # Directory names. May also be specified as -d. 
    disabled # Names of disabled shell builtins. 
    enabled # Names of enabled shell builtins. 
    export # Names of exported shell variables. May also be specified as -e. 
    file # File names. May also be specified as -f. 
    function # Names of shell functions. 
    group # Group names. May also be specified as -g. 
    helptopic # Help topics as accepted by the help builtin. 
    hostname # Hostnames, as taken from the file specified by the HOSTFILE shell variable. 
    job # Job names, if job control is active. May also be specified as -j. 
    keyword # Shell reserved words. May also be specified as -k. 
    running # Names of running jobs, if job control is active. 
    service # Service names. May also be specified as -s. 
    setopt # Valid arguments for the -o option to the set builtin. 
    shopt # Shell option names as accepted by the shopt builtin. 
    signal # Signal names. 
    stopped # Names of stopped jobs, if job control is active. 
    user # User names. May also be specified as -u. 
    variable # Names of all shell variables. May also be specified as -v. 

-C command # command is executed in a subshell environment, and its output is used as the possible completions.
-F function # The shell function function is executed in the current shell environment. When the function is executed, the first argument ($1) is the name of the command whose arguments are being completed, the second argument ($2) is the word being completed, and the third argument ($3) is the word preceding the word being completed on the current command line. When it finishes, the possible completions are retrieved from the value of the COMPREPLY # array variable.
-G globpat # The pathname expansion pattern globpat is expanded to generate the possible completions.
-P prefix # prefix is added at the beginning of each possible completion after all other options have been applied.
-S suffix # suffix is appended to each possible completion after all other options have been applied.
-W wordlist # The wordlist is split using the characters in the IFS special variable as delimiters, and each resultant word is expanded. The possible completions are the members of the resultant list which match the word being completed.
-X filterpat # filterpat is a pattern as used for pathname expansion. It is applied to the list of possible completions generated by the preceding options and arguments, and each completion matching filterpat is removed from the list. A leading ! in filterpat negates the pattern; in this case, any completion not matching filterpat is removed.

extra

complete -A directory $cmd # provide completion for directory
complete -d $cmd # provide completion for directory
complete -D $cmd # provide completion for directory
complete -f $cmd # provide completion for file
complete -W "$words" $cmd # Wordlist, provide the list of words for completion to command $cmd
complete -F _foo $cmd # use function _foo_comp to register completions for command $cmd
compopt [-o option] [-DE] [+o option] [name]
Modify completion options for each name according to the options, or for the currently-executing completion if no names are supplied. If no options are given, display the completion options for each name or the current completion. The possible values of option are those valid for the complete builtin described above. The -D option indicates that the remaining options should apply to the ``default'' command completion; that is, completion attempted on a command for which no completion has previously been defined. The -E option indicates that the remaining options should apply to ``empty'' command completion; that is, completion attempted on a blank line.

The return value is true unless an invalid option is supplied, an attempt is made to modify the options for a name for which no completion specification exists, or an output error occurs. 

variables

COMP_WORDS # an array of all the words typed after the name of the program the compspec belongs to
COMP_CWORD # an index of the COMP_WORDS array pointing to the word the current cursor is at—in other words
COMP_LINE # the current command line

tips

exec bash # reload completions
#!/usr/bin/env bash
#
# Bash completion function for the 'gh' command.
# gh is a github bash command available from https://cli.github.com
_gh()
{
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[COMP_CWORD-1]}
# for debugging
#echo -e "COMP_CWORD=${COMP_CWORD} \nCOMP_WORDS=${COMP_WORDS[*]} \nprev=${prev} \ncur=${cur}" >> /tmp/gh
if [ "${prev}" = gh ]; then
local opts=$(gh -h 2>/dev/null | sed -n 's|^ *\([a-z]\+\): .*$|\1|p')
elif [[ "${cur}" =~ --.* ]]; then
local opts=$(${COMP_LINE%%--*} -h 2>&1 | sed -n 's|^.*\(--[a-z_-]\+\).*$|\1|p')
else
local opts=$(gh ${prev} -h 2>/dev/null | sed -n 's|^ *\([a-z]\+\): .*$|\1|p')
fi
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
}
command -v gh >/dev/null && complete -F _gh gh
#!/usr/bin/env bash
#
# Bash completion function for script 'haconf' command.
# haconf is a personal command to manage haproxy configuration with splited files
_haconf()
{
local path_enabled="/etc/haproxy/conf-enabled"
local path_available="/etc/haproxy/conf-available"
__disabled() {
local confs conf notused
confs="$(ls "${path_available}")"
for conf in ${confs}; do
! [ -h "${path_enabled}/${conf}" ] && notused="${notused} ${conf}"
done
echo ${notused}
}
__enabled() {
ls ${path_enabled}
}
COMPREPLY=()
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[COMP_CWORD-1]}
# primary commans
local opts='check clear enable disable list reload'
# level 1 for commands
if [ $COMP_CWORD -eq 1 ]; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
# level 2 for arguments
else
case $prev in
enable)
COMPREPLY=( $(compgen -W "$(__disabled)" -- "${cur}" ) )
return 0
;;
disable)
COMPREPLY=( $(compgen -W "$(__enabled)" -- "${cur}" ) )
return 0
;;
esac
fi
}
complete -F _haconf haconf
#!/usr/bin/env bash
#
# Bash completion function for script 'qemu-img' command.
# qemu-img is a bash command to manage disk from qemu.
_qemuimg()
{
COMPREPLY=()
local cur=${COMP_WORDS[COMP_CWORD]}
local prev="${COMP_WORDS[COMP_CWORD-1]}"
local opts='amend bench bitmap check commit compare convert create dd info map measure snapshot rebase resize'
local formats='blkdebug blklogwrites blkverify bochs cloop compress copy-before-write copy-on-read dmg file ftp ftps gluster host_cdrom host_device http https iscsi iser luks nbd nfs null-aio null
-co nvme parallels preallocate qcow qcow2 qed quorum raw rbd replication snapshot-access ssh throttle vdi vhdx vmdk vpc vvfat'
#echo "COMP_LINE=$COMP_LINE" >> /tmp/qemu
#echo "COMP_WORDS=$COMP_WORDS[@] | COMP_CWORD=$COMP_CWORD" >> /tmp/qemu
#echo "cur=$cur | prev=$prev" >> /tmp/qemu
if [ ${COMP_CWORD} -eq 1 ]; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}" ) )
return 0
elif [[ $prev =~ -[oOf] ]]; then
COMPREPLY=( $(compgen -W "${formats}" -- "${cur}" ) )
else
compopt -o plusdirs
COMPREPLY=( $(compgen -f -- "${cur}") )
fi
} &&
complete -F _qemuimg qemu-img
#!/usr/bin/env bash
#
# Bash completion function for the 'vol2'.
# vol2 is a symbolic link to vol2.py, the 2.x version of the forensic program 'volatility' (memory dump file analyser)
# To create it use the following command by replacing "/usr/local/bin/vol.py" by the path of vol.py in your system:
# sudo ln -s /usr/local/bin/vol.py /usr/local/bin/vol2
_vol2()
{
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[COMP_CWORD-1]}
# for debugging
#echo -e "COMP_CWORD=${COMP_CWORD} \nCOMP_WORDS=${COMP_WORDS[*]} \nprev=${prev} \ncur=${cur} " >> /tmp/vol2
# global session variable
[ -z "${BC_VOL2_INFO}" ] && BC_VOL2_INFO=$(vol2 --info 2>/dev/null)
# plugins
local plugins=$(echo "${BC_VOL2_INFO}" | sed -n '/^Plugins/,/^$/ p' | tail -n+3 | cut -f1 -d' ' | xargs)
# profiles
local profiles=$(echo "${BC_VOL2_INFO}" | sed -n '/^Profiles$/,/^$/p' | awk '{print $1}' | sed '1,2d' | xargs)
if [ "${cur}" = - ]; then
local opts='-g -h -k -d -f -l -v -w'
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
elif [[ "${cur}" =~ --.* ]]; then
local opts='--cache --cache-directory --conf-file --cookie --debug --dtb --filename --force --help --info --info --kdbg --kpcr --location --output --output-file --physical_shift --plugins --profile --shift --tz --verbose --virtual_shift --write'
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
elif [[ "${prev}" = --profile ]]; then
COMPREPLY=( $(compgen -W "${profiles}" -- "${cur}") )
elif [[ "${prev}" =~ -(f|-cache-directory|-conf-file|-output-file|-plugins) ]]; then
compopt -o plusdirs
COMPREPLY=( $(compgen -f -- "${cur}") )
else
COMPREPLY=( $(compgen -W "${plugins}" -- "${cur}") )
fi
} && complete -F _vol2 vol2
#!/usr/bin/env bash
#
# Bash completion function for the 'vol3'.
# vol3 is a symbolic link to volatility.py, the 3.x version of the forensic program 'volatility' (memory dump file analyser)
# To create it use the following command by replacing "/usr/local/bin/volatility.py" by the path of vol in your system:
# sudo ln -s ${USER}/.local/bin/vol ${USER}/.local/bin/vol3
#
# You can choose on of 2 methods for completion:
# _vol3_v1 (default) give you a hierarchical view (lighter for reading)
# _vol3_v2 give you a full chain for completion (a little bit heavy to read)
# Hierachical view for completion
_vol3_v1() {
if [[ "${prev}" =~ -(c|f|o|p|s|-cache-path|-config|-file|-output-dir|-plugin-dirs|-symbol-dirs) ]]; then
compopt -o plusdirs
COMPREPLY=( $(compgen -f -- "${cur}") )
elif [[ "${prev}" =~ -(r|-renderer) ]]; then
local opts="csv json jsonl quick pretty"
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
elif [[ "${cur}" =~ --.* ]]; then
local opts=$(echo "$BC_VOL3_HELP" | sed -n 's|^ *\(-\)[^-]*\(-[a-z-]\+\).*$|\1\2|p' | sed s/---/--/ | sort -u)
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
else
if echo "${plugins_all}" | grep -q "^${prev%%.*}\."; then
COMPREPLY=()
else
compopt -o nospace
if echo "${plugins_all}" | grep -q "^${cur%%.*}\." ; then
plugins=$(echo "${plugins_all}" | grep ^${cur%.*}.*$ | sed "s|^${cur%\.*}\.||" | cut -d. -f1 | sort -u | xargs)
COMPREPLY=( ${cur%.*}.$(compgen -W "${plugins}" -- "${cur##*.}") )
else
plugins=$(echo "${plugins_all}" | sed 's|^\([^\.]\+\)\..*$|\1.|')
COMPREPLY=( $(compgen -W "${plugins}" -- "${cur}") )
fi
fi
fi
}
# Complete chain for completion
_vol3_v2() {
if [[ "${prev}" =~ -(c|f|o|p|s|-cache-path|-config|-file|-output-dir|-plugin-dirs|-symbol-dirs) ]]; then
compopt -o plusdirs
COMPREPLY=( $(compgen -f -- "${cur}") )
elif [[ "${prev}" =~ -(r|-renderer) ]]; then
local opts="csv json jsonl quick pretty"
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
elif [[ "${cur}" =~ --.* ]]; then
local opts=$(echo "$BC_VOL3_HELP" | sed -n 's|^ *\(-\)[^-]*\(-[a-z-]\+\).*$|\1\2|p' | sed s/---/--/ | sort -u)
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
else
if echo "${plugins_all}" | grep -q "^${prev%%.*}\."; then
COMPREPLY=()
else
if echo "${plugins_all}" | grep -q "^${cur%%.*}\."; then
plugins=$(echo "${plugins_all}" | grep ^${cur} | xargs)
else
plugins=${plugins_base}
fi
compopt -o nospace
COMPREPLY=( $(compgen -W "${plugins_all}" -- "${cur}") )
fi
fi
}
_vol3()
{
COMPREPLY=()
local cur=${COMP_WORDS[COMP_CWORD]}
local prev=${COMP_WORDS[COMP_CWORD-1]}
# for debugging
#echo -e "COMP_CWORD=${COMP_CWORD} \nCOMP_WORDS=${COMP_WORDS[*]} \nprev=${prev} \ncur=${cur} " >> /tmp/vol3
[ -z "${BC_VOL3_HELP}" ] && BC_VOL3_HELP=$(vol3 --help)
# all
plugins_all=$(echo "${BC_VOL3_HELP}" | sed -n '/^ *plugin$/,/^$/p' | sed 1d | grep -v '^ ' | awk '{print $1}')
# first rank
local plugins_base=$(echo "${plugins_all}" | sed 's|^\([^\.]\+\)\..*$|\1.|' | sort -u | xargs)
_vol3_v1 # _vol3_v1 or _vol3_v2
} &&
complete -F _vol3 vol3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment