Skip to content

Instantly share code, notes, and snippets.

@alexanderankin
Last active December 11, 2023 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexanderankin/eab32ba5fe9ed761d9a0011d21a584a8 to your computer and use it in GitHub Desktop.
Save alexanderankin/eab32ba5fe9ed761d9a0011d21a584a8 to your computer and use it in GitHub Desktop.
/usr/share/bash-completion/completions/ssh (mv ssh ./.config/bash_completion.d/ ; echo '. ~/.bash_completion' >> .bashrc)
# -*- shell-script -*-
#
# bash_completion - programmable completion functions for bash 4.2+
#
# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
# © 2009-2020, Bash Completion Maintainers
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# The latest version of this software can be obtained here:
#
# https://github.com/scop/bash-completion
BASH_COMPLETION_VERSINFO=(2 11)
if [[ $- == *v* ]]; then
BASH_COMPLETION_ORIGINAL_V_VALUE="-v"
else
BASH_COMPLETION_ORIGINAL_V_VALUE="+v"
fi
if [[ ${BASH_COMPLETION_DEBUG-} ]]; then
set -v
else
set +v
fi
# Blacklisted completions, causing problems with our code.
#
_blacklist_glob='@(acroread.sh)'
# 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
# start of section containing compspecs that can be handled within bash
# user commands see only users
complete -u groups slay w sux
# bg completes with stopped jobs
complete -A stopped -P '"%' -S '"' bg
# other job commands
complete -j -P '"%' -S '"' fg jobs disown
# readonly and unset complete with shell variables
complete -v 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
# type and which complete on commands
complete -c command type which
# builtin completes on builtins
complete -b builtin
# start of section containing completion functions called by other functions
# Check if we're running on the given userland
# @param $1 userland to check for
_userland()
{
local userland=$(uname -s)
[[ $userland == @(Linux|GNU/*) ]] && userland=GNU
[[ $userland == "$1" ]]
}
# This function sets correct SysV init directories
#
_sysvdirs()
{
sysvdirs=()
[[ -d /etc/rc.d/init.d ]] && sysvdirs+=(/etc/rc.d/init.d)
[[ -d /etc/init.d ]] && sysvdirs+=(/etc/init.d)
# Slackware uses /etc/rc.d
[[ -f /etc/slackware-version ]] && sysvdirs=(/etc/rc.d)
return 0
}
# This function checks whether we have a given program on the system.
#
_have()
{
# Completions for system administrator commands are installed as well in
# case completion is attempted via `sudo command ...'.
PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type $1 &>/dev/null
}
# Backwards compatibility for compat completions that use have().
# @deprecated should no longer be used; generally not needed with dynamically
# loaded completions, and _have is suitable for runtime use.
have()
{
unset -v have
_have $1 && have=yes
}
# This function checks whether a given readline variable
# is `on'.
#
_rl_enabled()
{
[[ "$(bind -v)" == *$1+([[:space:]])on* ]]
}
# This function shell-quotes the argument
quote()
{
local quoted=${1//\'/\'\\\'\'}
printf "'%s'" "$quoted"
}
# @see _quote_readline_by_ref()
quote_readline()
{
local ret
_quote_readline_by_ref "$1" ret
printf %s "$ret"
} # quote_readline()
# This function shell-dequotes the argument
dequote()
{
eval printf %s "$1" 2>/dev/null
}
# Assign variable one scope above the caller
# Usage: local "$1" && _upvar $1 "value(s)"
# Param: $1 Variable name to assign value to
# Param: $* Value(s) to assign. If multiple values, an array is
# assigned, otherwise a single value is assigned.
# NOTE: For assigning multiple variables, use '_upvars'. Do NOT
# use multiple '_upvar' calls, since one '_upvar' call might
# reassign a variable to be used by another '_upvar' call.
# See: https://fvue.nl/wiki/Bash:_Passing_variables_by_reference
_upvar()
{
echo "bash_completion: $FUNCNAME: deprecated function," \
"use _upvars instead" >&2
if unset -v "$1"; then # Unset & validate varname
if (($# == 2)); then
eval $1=\"\$2\" # Return single value
else
eval $1=\(\"\$"{@:2}"\"\) # Return array
fi
fi
}
# Assign variables one scope above the caller
# Usage: local varname [varname ...] &&
# _upvars [-v varname value] | [-aN varname [value ...]] ...
# Available OPTIONS:
# -aN Assign next N values to varname as array
# -v Assign single value to varname
# Return: 1 if error occurs
# See: https://fvue.nl/wiki/Bash:_Passing_variables_by_reference
_upvars()
{
if ! (($#)); then
echo "bash_completion: $FUNCNAME: usage: $FUNCNAME" \
"[-v varname value] | [-aN varname [value ...]] ..." >&2
return 2
fi
while (($#)); do
case $1 in
-a*)
# Error checking
[[ ${1#-a} ]] || {
echo "bash_completion: $FUNCNAME:" \
"\`$1': missing number specifier" >&2
return 1
}
printf %d "${1#-a}" &>/dev/null || {
echo bash_completion: \
"$FUNCNAME: \`$1': invalid number specifier" >&2
return 1
}
# Assign array of -aN elements
[[ "$2" ]] && unset -v "$2" && eval $2=\(\"\$"{@:3:${1#-a}}"\"\) &&
shift $((${1#-a} + 2)) || {
echo bash_completion: \
"$FUNCNAME: \`$1${2+ }$2': missing argument(s)" \
>&2
return 1
}
;;
-v)
# Assign single value
[[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" &&
shift 3 || {
echo "bash_completion: $FUNCNAME: $1:" \
"missing argument(s)" >&2
return 1
}
;;
*)
echo "bash_completion: $FUNCNAME: $1: invalid option" >&2
return 1
;;
esac
done
}
# Reassemble command line words, excluding specified characters from the
# list of word completion separators (COMP_WORDBREAKS).
# @param $1 chars Characters out of $COMP_WORDBREAKS which should
# NOT be considered word breaks. This is useful for things like scp where
# we want to return host:path and not only path, so we would pass the
# colon (:) as $1 here.
# @param $2 words Name of variable to return words to
# @param $3 cword Name of variable to return cword to
#
__reassemble_comp_words_by_ref()
{
local exclude i j line ref
# Exclude word separator characters?
if [[ $1 ]]; then
# Yes, exclude word separator characters;
# Exclude only those characters, which were really included
exclude="[${1//[^$COMP_WORDBREAKS]/}]"
fi
# Default to cword unchanged
printf -v "$3" %s "$COMP_CWORD"
# Are characters excluded which were former included?
if [[ -v exclude ]]; then
# Yes, list of word completion separators has shrunk;
line=$COMP_LINE
# Re-assemble words to complete
for ((i = 0, j = 0; i < ${#COMP_WORDS[@]}; i++, j++)); do
# Is current word not word 0 (the command itself) and is word not
# empty and is word made up of just word separator characters to
# be excluded and is current word not preceded by whitespace in
# original line?
while [[ $i -gt 0 && ${COMP_WORDS[i]} == +($exclude) ]]; do
# Is word separator not preceded by whitespace in original line
# and are we not going to append to word 0 (the command
# itself), then append to current word.
[[ $line != [[:blank:]]* ]] && ((j >= 2)) && ((j--))
# Append word separator to current or new word
ref="$2[$j]"
printf -v "$ref" %s "${!ref-}${COMP_WORDS[i]}"
# Indicate new cword
((i == COMP_CWORD)) && printf -v "$3" %s "$j"
# Remove optional whitespace + word separator from line copy
line=${line#*"${COMP_WORDS[i]}"}
# Start new word if word separator in original line is
# followed by whitespace.
[[ $line == [[:blank:]]* ]] && ((j++))
# Indicate next word if available, else end *both* while and
# for loop
((i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2
done
# Append word to current word
ref="$2[$j]"
printf -v "$ref" %s "${!ref-}${COMP_WORDS[i]}"
# Remove optional whitespace + word from line copy
line=${line#*"${COMP_WORDS[i]}"}
# Indicate new cword
((i == COMP_CWORD)) && printf -v "$3" %s "$j"
done
((i == COMP_CWORD)) && printf -v "$3" %s "$j"
else
# No, list of word completions separators hasn't changed;
for i in "${!COMP_WORDS[@]}"; do
printf -v "$2[i]" %s "${COMP_WORDS[i]}"
done
fi
} # __reassemble_comp_words_by_ref()
# @param $1 exclude Characters out of $COMP_WORDBREAKS which should NOT be
# considered word breaks. This is useful for things like scp where
# we want to return host:path and not only path, so we would pass the
# colon (:) as $1 in this case.
# @param $2 words Name of variable to return words to
# @param $3 cword Name of variable to return cword to
# @param $4 cur Name of variable to return current word to complete to
# @see __reassemble_comp_words_by_ref()
__get_cword_at_cursor_by_ref()
{
local cword words=()
__reassemble_comp_words_by_ref "$1" words cword
local i cur="" index=$COMP_POINT lead=${COMP_LINE:0:COMP_POINT}
# Cursor not at position 0 and not leaded by just space(s)?
if [[ $index -gt 0 && ($lead && ${lead//[[:space:]]/}) ]]; then
cur=$COMP_LINE
for ((i = 0; i <= cword; ++i)); do
# Current word fits in $cur, and $cur doesn't match cword?
while [[ ${#cur} -ge ${#words[i]} && \
${cur:0:${#words[i]}} != "${words[i]-}" ]]; do
# Strip first character
cur="${cur:1}"
# Decrease cursor position, staying >= 0
((index > 0)) && ((index--))
done
# Does found word match cword?
if ((i < cword)); then
# No, cword lies further;
local old_size=${#cur}
cur="${cur#"${words[i]}"}"
local new_size=${#cur}
((index -= old_size - new_size))
fi
done
# Clear $cur if just space(s)
[[ $cur && ! ${cur//[[:space:]]/} ]] && cur=
# Zero $index if negative
((index < 0)) && index=0
fi
local "$2" "$3" "$4" && _upvars -a${#words[@]} $2 ${words+"${words[@]}"} \
-v $3 "$cword" -v $4 "${cur:0:index}"
}
# Get the word to complete and optional previous words.
# This is nicer than ${COMP_WORDS[COMP_CWORD]}, since it handles cases
# where the user is completing in the middle of a word.
# (For example, if the line is "ls foobar",
# and the cursor is here --------> ^
# Also one is able to cross over possible wordbreak characters.
# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
# Available VARNAMES:
# cur Return cur via $cur
# prev Return prev via $prev
# words Return words via $words
# cword Return cword via $cword
#
# Available OPTIONS:
# -n EXCLUDE Characters out of $COMP_WORDBREAKS which should NOT be
# considered word breaks. This is useful for things like scp
# where we want to return host:path and not only path, so we
# would pass the colon (:) as -n option in this case.
# -c VARNAME Return cur via $VARNAME
# -p VARNAME Return prev via $VARNAME
# -w VARNAME Return words via $VARNAME
# -i VARNAME Return cword via $VARNAME
#
# Example usage:
#
# $ _get_comp_words_by_ref -n : cur prev
#
_get_comp_words_by_ref()
{
local exclude flag i OPTIND=1
local cur cword words=()
local upargs=() upvars=() vcur vcword vprev vwords
while getopts "c:i:n:p:w:" flag "$@"; do
case $flag in
c) vcur=$OPTARG ;;
i) vcword=$OPTARG ;;
n) exclude=$OPTARG ;;
p) vprev=$OPTARG ;;
w) vwords=$OPTARG ;;
*)
echo "bash_completion: $FUNCNAME: usage error" >&2
return 1
;;
esac
done
while [[ $# -ge $OPTIND ]]; do
case ${!OPTIND} in
cur) vcur=cur ;;
prev) vprev=prev ;;
cword) vcword=cword ;;
words) vwords=words ;;
*)
echo "bash_completion: $FUNCNAME: \`${!OPTIND}':" \
"unknown argument" >&2
return 1
;;
esac
((OPTIND += 1))
done
__get_cword_at_cursor_by_ref "${exclude-}" words cword cur
[[ -v vcur ]] && {
upvars+=("$vcur")
upargs+=(-v $vcur "$cur")
}
[[ -v vcword ]] && {
upvars+=("$vcword")
upargs+=(-v $vcword "$cword")
}
[[ -v vprev && $cword -ge 1 ]] && {
upvars+=("$vprev")
upargs+=(-v $vprev "${words[cword - 1]}")
}
[[ -v vwords ]] && {
upvars+=("$vwords")
upargs+=(-a${#words[@]} $vwords ${words+"${words[@]}"})
}
((${#upvars[@]})) && local "${upvars[@]}" && _upvars "${upargs[@]}"
}
# Get the word to complete.
# This is nicer than ${COMP_WORDS[COMP_CWORD]}, since it handles cases
# where the user is completing in the middle of a word.
# (For example, if the line is "ls foobar",
# and the cursor is here --------> ^
# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be
# considered word breaks. This is useful for things like scp where
# we want to return host:path and not only path, so we would pass the
# colon (:) as $1 in this case.
# @param $2 integer Index number of word to return, negatively offset to the
# current word (default is 0, previous is 1), respecting the exclusions
# given at $1. For example, `_get_cword "=:" 1' returns the word left of
# the current word, respecting the exclusions "=:".
# @deprecated Use `_get_comp_words_by_ref cur' instead
# @see _get_comp_words_by_ref()
_get_cword()
{
local LC_CTYPE=C
local cword words
__reassemble_comp_words_by_ref "${1-}" words cword
# return previous word offset by $2
if [[ ${2-} && ${2//[^0-9]/} ]]; then
printf "%s" "${words[cword - $2]}"
elif ((${#words[cword]} == 0 && COMP_POINT == ${#COMP_LINE})); then
: # nothing
else
local i
local cur="$COMP_LINE"
local index="$COMP_POINT"
for ((i = 0; i <= cword; ++i)); do
# Current word fits in $cur, and $cur doesn't match cword?
while [[ ${#cur} -ge ${#words[i]} && \
${cur:0:${#words[i]}} != "${words[i]}" ]]; do
# Strip first character
cur="${cur:1}"
# Decrease cursor position, staying >= 0
((index > 0)) && ((index--))
done
# Does found word match cword?
if ((i < cword)); then
# No, cword lies further;
local old_size="${#cur}"
cur="${cur#${words[i]}}"
local new_size="${#cur}"
((index -= old_size - new_size))
fi
done
if [[ ${words[cword]:0:${#cur}} != "$cur" ]]; then
# We messed up! At least return the whole word so things
# keep working
printf "%s" "${words[cword]}"
else
printf "%s" "${cur:0:index}"
fi
fi
} # _get_cword()
# Get word previous to the current word.
# This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4
# will properly return the previous word with respect to any given exclusions to
# COMP_WORDBREAKS.
# @deprecated Use `_get_comp_words_by_ref cur prev' instead
# @see _get_comp_words_by_ref()
#
_get_pword()
{
if ((COMP_CWORD >= 1)); then
_get_cword "${@:-}" 1
fi
}
# If the word-to-complete contains a colon (:), left-trim COMPREPLY items with
# word-to-complete.
# With a colon in COMP_WORDBREAKS, words containing
# colons are always completed as entire words if the word to complete contains
# a colon. This function fixes this, by removing the colon-containing-prefix
# from COMPREPLY items.
# The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in
# your .bashrc:
#
# # Remove colon (:) from list of word completion separators
# COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
#
# See also: Bash FAQ - E13) Why does filename completion misbehave if a colon
# appears in the filename? - https://tiswww.case.edu/php/chet/bash/FAQ
# @param $1 current word to complete (cur)
# @modifies global array $COMPREPLY
#
__ltrim_colon_completions()
{
if [[ $1 == *:* && $COMP_WORDBREAKS == *:* ]]; then
# Remove colon-word prefix from COMPREPLY items
local colon_word=${1%"${1##*:}"}
local i=${#COMPREPLY[*]}
while ((i-- > 0)); do
COMPREPLY[i]=${COMPREPLY[i]#"$colon_word"}
done
fi
} # __ltrim_colon_completions()
# This function quotes the argument in a way so that readline dequoting
# results in the original argument. This is necessary for at least
# `compgen' which requires its arguments quoted/escaped:
#
# $ ls "a'b/"
# c
# $ compgen -f "a'b/" # Wrong, doesn't return output
# $ compgen -f "a\'b/" # Good
# a\'b/c
#
# See also:
# - https://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
# - https://www.mail-archive.com/bash-completion-devel@lists.alioth.debian.org/msg01944.html
# @param $1 Argument to quote
# @param $2 Name of variable to return result to
_quote_readline_by_ref()
{
if [ -z "$1" ]; then
# avoid quoting if empty
printf -v $2 %s "$1"
elif [[ $1 == \'* ]]; then
# Leave out first character
printf -v $2 %s "${1:1}"
elif [[ $1 == \~* ]]; then
# avoid escaping first ~
printf -v $2 \~%q "${1:1}"
else
printf -v $2 %q "$1"
fi
# If result becomes quoted like this: $'string', re-evaluate in order to
# drop the additional quoting. See also:
# https://www.mail-archive.com/bash-completion-devel@lists.alioth.debian.org/msg01942.html
[[ ${!2} == \$* ]] && eval $2=${!2}
} # _quote_readline_by_ref()
# This function performs file and directory completion. It's better than
# simply using 'compgen -f', because it honours spaces in filenames.
# @param $1 If `-d', complete only on directories. Otherwise filter/pick only
# completions with `.$1' and the uppercase version of it as file
# extension.
#
_filedir()
{
local IFS=$'\n'
_tilde "${cur-}" || return
local -a toks
local reset arg=${1-}
if [[ $arg == -d ]]; then
reset=$(shopt -po noglob)
set -o noglob
toks=($(compgen -d -- "${cur-}"))
IFS=' '
$reset
IFS=$'\n'
else
local quoted
_quote_readline_by_ref "${cur-}" quoted
# Munge xspec to contain uppercase version too
# https://lists.gnu.org/archive/html/bug-bash/2010-09/msg00036.html
# news://news.gmane.io/4C940E1C.1010304@case.edu
local xspec=${arg:+"!*.@($arg|${arg^^})"} plusdirs=()
# Use plusdirs to get dir completions if we have a xspec; if we don't,
# there's no need, dirs come along with other completions. Don't use
# plusdirs quite yet if fallback is in use though, in order to not ruin
# the fallback condition with the "plus" dirs.
local opts=(-f -X "$xspec")
[[ $xspec ]] && plusdirs=(-o plusdirs)
[[ ${COMP_FILEDIR_FALLBACK-} || -z ${plusdirs-} ]] ||
opts+=("${plusdirs[@]}")
reset=$(shopt -po noglob)
set -o noglob
toks+=($(compgen "${opts[@]}" -- $quoted))
IFS=' '
$reset
IFS=$'\n'
# Try without filter if it failed to produce anything and configured to
[[ -n ${COMP_FILEDIR_FALLBACK-} && -n $arg && ${#toks[@]} -lt 1 ]] && {
reset=$(shopt -po noglob)
set -o noglob
toks+=($(compgen -f ${plusdirs+"${plusdirs[@]}"} -- $quoted))
IFS=' '
$reset
IFS=$'\n'
}
fi
if ((${#toks[@]} != 0)); then
# 2>/dev/null for direct invocation, e.g. in the _filedir unit test
compopt -o filenames 2>/dev/null
COMPREPLY+=("${toks[@]}")
fi
} # _filedir()
# This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it
# easier to support both "--foo bar" and "--foo=bar" style completions.
# `=' should have been removed from COMP_WORDBREAKS when setting $cur for
# this to be useful.
# Returns 0 if current option was split, 1 otherwise.
#
_split_longopt()
{
if [[ $cur == --?*=* ]]; then
# Cut also backslash before '=' in case it ended up there
# for some reason.
prev="${cur%%?(\\)=*}"
cur="${cur#*=}"
return 0
fi
return 1
}
# Complete variables.
# @return True (0) if variables were completed,
# False (> 0) if not.
_variables()
{
if [[ $cur =~ ^(\$(\{[!#]?)?)([A-Za-z0-9_]*)$ ]]; then
# Completing $var / ${var / ${!var / ${#var
if [[ $cur == '${'* ]]; then
local arrs vars
vars=($(compgen -A variable -P ${BASH_REMATCH[1]} -S '}' -- ${BASH_REMATCH[3]}))
arrs=($(compgen -A arrayvar -P ${BASH_REMATCH[1]} -S '[' -- ${BASH_REMATCH[3]}))
if ((${#vars[@]} == 1 && ${#arrs[@]} != 0)); then
# Complete ${arr with ${array[ if there is only one match, and that match is an array variable
compopt -o nospace
COMPREPLY+=(${arrs[*]})
else
# Complete ${var with ${variable}
COMPREPLY+=(${vars[*]})
fi
else
# Complete $var with $variable
COMPREPLY+=($(compgen -A variable -P '$' -- "${BASH_REMATCH[3]}"))
fi
return 0
elif [[ $cur =~ ^(\$\{[#!]?)([A-Za-z0-9_]*)\[([^]]*)$ ]]; then
# Complete ${array[i with ${array[idx]}
local IFS=$'\n'
COMPREPLY+=($(compgen -W '$(printf %s\\n "${!'${BASH_REMATCH[2]}'[@]}")' \
-P "${BASH_REMATCH[1]}${BASH_REMATCH[2]}[" -S ']}' -- "${BASH_REMATCH[3]}"))
# Complete ${arr[@ and ${arr[*
if [[ ${BASH_REMATCH[3]} == [@*] ]]; then
COMPREPLY+=("${BASH_REMATCH[1]}${BASH_REMATCH[2]}[${BASH_REMATCH[3]}]}")
fi
__ltrim_colon_completions "$cur" # array indexes may have colons
return 0
elif [[ $cur =~ ^\$\{[#!]?[A-Za-z0-9_]*\[.*\]$ ]]; then
# Complete ${array[idx] with ${array[idx]}
COMPREPLY+=("$cur}")
__ltrim_colon_completions "$cur"
return 0
fi
return 1
}
# Complete assignment of various known environment variables.
# The word to be completed is expected to contain the entire
# assignment, including the variable name and the "=". See related
# parameters to _init_completion.
#
# @param $1 variable assignment to be completed
# @return True (0) if variable value completion was attempted,
# False (> 0) if not.
_variable_assignments()
{
local cur=${1-}
if [[ $cur =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
prev=${BASH_REMATCH[1]}
cur=${BASH_REMATCH[2]}
else
return 1
fi
case $prev in
TZ)
cur=/usr/share/zoneinfo/$cur
_filedir
for i in "${!COMPREPLY[@]}"; do
if [[ ${COMPREPLY[i]} == *.tab ]]; then
unset 'COMPREPLY[i]'
continue
elif [[ -d ${COMPREPLY[i]} ]]; then
COMPREPLY[i]+=/
compopt -o nospace
fi
COMPREPLY[i]=${COMPREPLY[i]#/usr/share/zoneinfo/}
done
;;
TERM)
_terms
;;
LANG | LC_*)
COMPREPLY=($(compgen -W '$(locale -a 2>/dev/null)' \
-- "$cur"))
;;
*)
_variables && return 0
_filedir
;;
esac
return 0
}
# Initialize completion and deal with various general things: do file
# and variable completion where appropriate, and adjust prev, words,
# and cword as if no redirections exist so that completions do not
# need to deal with them. Before calling this function, make sure
# cur, prev, words, and cword are local, ditto split if you use -s.
#
# Options:
# -n EXCLUDE Passed to _get_comp_words_by_ref -n with redirection chars
# -e XSPEC Passed to _filedir as first arg for stderr redirections
# -o XSPEC Passed to _filedir as first arg for other output redirections
# -i XSPEC Passed to _filedir as first arg for stdin redirections
# -s Split long options with _split_longopt, implies -n =
# @return True (0) if completion needs further processing,
# False (> 0) no further processing is necessary.
#
_init_completion()
{
local exclude="" flag outx errx inx OPTIND=1
while getopts "n:e:o:i:s" flag "$@"; do
case $flag in
n) exclude+=$OPTARG ;;
e) errx=$OPTARG ;;
o) outx=$OPTARG ;;
i) inx=$OPTARG ;;
s)
split=false
exclude+==
;;
*)
echo "bash_completion: $FUNCNAME: usage error" >&2
return 1
;;
esac
done
COMPREPLY=()
local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)"
_get_comp_words_by_ref -n "$exclude<>&" cur prev words cword
# Complete variable names.
_variables && return 1
# Complete on files if current is a redirect possibly followed by a
# filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">".
# shellcheck disable=SC2053
if [[ $cur == $redir* || ${prev-} == $redir ]]; then
local xspec
case $cur in
2'>'*) xspec=${errx-} ;;
*'>'*) xspec=${outx-} ;;
*'<'*) xspec=${inx-} ;;
*)
case $prev in
2'>'*) xspec=${errx-} ;;
*'>'*) xspec=${outx-} ;;
*'<'*) xspec=${inx-} ;;
esac
;;
esac
cur="${cur##$redir}"
_filedir $xspec
return 1
fi
# Remove all redirections so completions don't have to deal with them.
local i skip
for ((i = 1; i < ${#words[@]}; )); do
if [[ ${words[i]} == $redir* ]]; then
# If "bare" redirect, remove also the next word (skip=2).
# shellcheck disable=SC2053
[[ ${words[i]} == $redir ]] && skip=2 || skip=1
words=("${words[@]:0:i}" "${words[@]:i+skip}")
((i <= cword)) && ((cword -= skip))
else
((i++))
fi
done
((cword <= 0)) && return 1
prev=${words[cword - 1]}
[[ ${split-} ]] && _split_longopt && split=true
return 0
}
# Helper function for _parse_help and _parse_usage.
__parse_options()
{
local option option2 i IFS=$' \t\n,/|'
# Take first found long option, or first one (short) if not found.
option=
local -a array=($1)
for i in "${array[@]}"; do
case "$i" in
---*) break ;;
--?*)
option=$i
break
;;
-?*) [[ $option ]] || option=$i ;;
*) break ;;
esac
done
[[ $option ]] || return 0
IFS=$' \t\n' # affects parsing of the regexps below...
# Expand --[no]foo to --foo and --nofoo etc
if [[ $option =~ (\[((no|dont)-?)\]). ]]; then
option2=${option/"${BASH_REMATCH[1]}"/}
option2=${option2%%[<{().[]*}
printf '%s\n' "${option2/=*/=}"
option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"}
fi
option=${option%%[<{().[]*}
printf '%s\n' "${option/=*/=}"
}
# Parse GNU style help output of the given command.
# @param $1 command; if "-", read from stdin and ignore rest of args
# @param $2 command options (default: --help)
#
_parse_help()
{
eval local cmd="$(quote "$1")"
local line
{
case $cmd in
-) cat ;;
*) LC_ALL=C "$(dequote "$cmd")" ${2:---help} 2>&1 ;;
esac
} |
while read -r line; do
[[ $line == *([[:blank:]])-* ]] || continue
# transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc
while [[ $line =~ \
((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+([,_-]+[A-Z0-9]+)?(\.\.+)?\]? ]]; do
line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"}
done
__parse_options "${line// or /, }"
done
}
# Parse BSD style usage output (options in brackets) of the given command.
# @param $1 command; if "-", read from stdin and ignore rest of args
# @param $2 command options (default: --usage)
#
_parse_usage()
{
eval local cmd="$(quote "$1")"
local line match option i char
{
case $cmd in
-) cat ;;
*) LC_ALL=C "$(dequote "$cmd")" ${2:---usage} 2>&1 ;;
esac
} |
while read -r line; do
while [[ $line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do
match=${BASH_REMATCH[0]}
option=${BASH_REMATCH[1]}
case $option in
-?(\[)+([a-zA-Z0-9?]))
# Treat as bundled short options
for ((i = 1; i < ${#option}; i++)); do
char=${option:i:1}
[[ $char != '[' ]] && printf '%s\n' -$char
done
;;
*)
__parse_options "$option"
;;
esac
line=${line#*"$match"}
done
done
}
# This function completes on signal names (minus the SIG prefix)
# @param $1 prefix
_signals()
{
local -a sigs=($(compgen -P "${1-}" -A signal "SIG${cur#${1-}}"))
COMPREPLY+=("${sigs[@]/#${1-}SIG/${1-}}")
}
# This function completes on known mac addresses
#
_mac_addresses()
{
local re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}'
local PATH="$PATH:/sbin:/usr/sbin"
# Local interfaces
# - ifconfig on Linux: HWaddr or ether
# - ifconfig on FreeBSD: ether
# - ip link: link/ether
COMPREPLY+=($(
{
LC_ALL=C ifconfig -a || ip link show
} 2>/dev/null | command sed -ne \
"s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]].*/\1/p" -ne \
"s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" -ne \
"s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]].*|\2|p" -ne \
"s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]]*$|\2|p"
))
# ARP cache
COMPREPLY+=($({
arp -an || ip neigh show
} 2>/dev/null | command sed -ne \
"s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \
"s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p"))
# /etc/ethers
COMPREPLY+=($(command sed -ne \
"s/^[[:space:]]*\($re\)[[:space:]].*/\1/p" /etc/ethers 2>/dev/null))
COMPREPLY=($(compgen -W '${COMPREPLY[@]}' -- "$cur"))
__ltrim_colon_completions "$cur"
}
# This function completes on configured network interfaces
#
_configured_interfaces()
{
if [[ -f /etc/debian_version ]]; then
# Debian system
COMPREPLY=($(compgen -W "$(command sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p' \
/etc/network/interfaces /etc/network/interfaces.d/* 2>/dev/null)" \
-- "$cur"))
elif [[ -f /etc/SuSE-release ]]; then
# SuSE system
COMPREPLY=($(compgen -W "$(printf '%s\n' \
/etc/sysconfig/network/ifcfg-* |
command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" -- "$cur"))
elif [[ -f /etc/pld-release ]]; then
# PLD Linux
COMPREPLY=($(compgen -W "$(command ls -B \
/etc/sysconfig/interfaces |
command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" -- "$cur"))
else
# Assume Red Hat
COMPREPLY=($(compgen -W "$(printf '%s\n' \
/etc/sysconfig/network-scripts/ifcfg-* |
command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" -- "$cur"))
fi
}
# Local IP addresses.
# -4: IPv4 addresses only (default)
# -6: IPv6 addresses only
# -a: All addresses
#
_ip_addresses()
{
local n
case ${1-} in
-a) n='6\?' ;;
-6) n='6' ;;
*) n= ;;
esac
local PATH=$PATH:/sbin
local addrs=$({
LC_ALL=C ifconfig -a || ip addr show
} 2>/dev/null |
command sed -e 's/[[:space:]]addr:/ /' -ne \
"s|.*inet${n}[[:space:]]\{1,\}\([^[:space:]/]*\).*|\1|p")
COMPREPLY+=($(compgen -W "$addrs" -- "${cur-}"))
}
# This function completes on available kernels
#
_kernel_versions()
{
COMPREPLY=($(compgen -W '$(command ls /lib/modules)' -- "$cur"))
}
# This function completes on all available network interfaces
# -a: restrict to active interfaces only
# -w: restrict to wireless interfaces only
#
_available_interfaces()
{
local PATH=$PATH:/sbin
COMPREPLY=($({
if [[ ${1:-} == -w ]]; then
iwconfig
elif [[ ${1:-} == -a ]]; then
ifconfig || ip link show up
else
ifconfig -a || ip link show
fi
} 2>/dev/null | awk \
'/^[^ \t]/ { if ($1 ~ /^[0-9]+:/) { print $2 } else { print $1 } }'))
COMPREPLY=($(compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur"))
}
# Echo number of CPUs, falling back to 1 on failure.
_ncpus()
{
local var=NPROCESSORS_ONLN
[[ $OSTYPE == *linux* ]] && var=_$var
local n=$(getconf $var 2>/dev/null)
printf %s ${n:-1}
}
# Perform tilde (~) completion
# @return True (0) if completion needs further processing,
# False (> 0) if tilde is followed by a valid username, completions
# are put in COMPREPLY and no further processing is necessary.
_tilde()
{
local result=0
if [[ ${1-} == \~* && $1 != */* ]]; then
# Try generate ~username completions
COMPREPLY=($(compgen -P '~' -u -- "${1#\~}"))
result=${#COMPREPLY[@]}
# 2>/dev/null for direct invocation, e.g. in the _tilde unit test
((result > 0)) && compopt -o filenames 2>/dev/null
fi
return $result
}
# Expand variable starting with tilde (~)
# We want to expand ~foo/... to /home/foo/... to avoid problems when
# word-to-complete starting with a tilde is fed to commands and ending up
# quoted instead of expanded.
# Only the first portion of the variable from the tilde up to the first slash
# (~../) is expanded. The remainder of the variable, containing for example
# a dollar sign variable ($) or asterisk (*) is not expanded.
# Example usage:
#
# $ v="~"; __expand_tilde_by_ref v; echo "$v"
#
# Example output:
#
# v output
# -------- ----------------
# ~ /home/user
# ~foo/bar /home/foo/bar
# ~foo/$HOME /home/foo/$HOME
# ~foo/a b /home/foo/a b
# ~foo/* /home/foo/*
#
# @param $1 Name of variable (not the value of the variable) to expand
__expand_tilde_by_ref()
{
if [[ ${!1-} == \~* ]]; then
eval $1="$(printf ~%q "${!1#\~}")"
fi
} # __expand_tilde_by_ref()
# This function expands tildes in pathnames
#
_expand()
{
# Expand ~username type directory specifications. We want to expand
# ~foo/... to /home/foo/... to avoid problems when $cur starting with
# a tilde is fed to commands and ending up quoted instead of expanded.
case ${cur-} in
~*/*)
__expand_tilde_by_ref cur
;;
~*)
_tilde "$cur" ||
eval COMPREPLY[0]="$(printf ~%q "${COMPREPLY[0]#\~}")"
return ${#COMPREPLY[@]}
;;
esac
}
# Process ID related functions.
# for AIX and Solaris we use X/Open syntax, BSD for others.
if [[ $OSTYPE == *@(solaris|aix)* ]]; then
# This function completes on process IDs.
_pids()
{
COMPREPLY=($(compgen -W '$(command ps -efo pid | command sed 1d)' -- "$cur"))
}
_pgids()
{
COMPREPLY=($(compgen -W '$(command ps -efo pgid | command sed 1d)' -- "$cur"))
}
_pnames()
{
COMPREPLY=($(compgen -X '<defunct>' -W '$(command ps -efo comm | \
command sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u)' -- "$cur"))
}
else
_pids()
{
COMPREPLY=($(compgen -W '$(command ps axo pid=)' -- "$cur"))
}
_pgids()
{
COMPREPLY=($(compgen -W '$(command ps axo pgid=)' -- "$cur"))
}
# @param $1 if -s, don't try to avoid truncated command names
_pnames()
{
local -a procs
if [[ ${1-} == -s ]]; then
procs=($(command ps axo comm | command sed -e 1d))
else
local line i=-1 ifs=$IFS
IFS=$'\n'
local -a psout=($(command ps axo command=))
IFS=$ifs
for line in "${psout[@]}"; do
if ((i == -1)); then
# First line, see if it has COMMAND column header. For example
# the busybox ps does that, i.e. doesn't respect axo command=
if [[ $line =~ ^(.*[[:space:]])COMMAND([[:space:]]|$) ]]; then
# It does; store its index.
i=${#BASH_REMATCH[1]}
else
# Nope, fall through to "regular axo command=" parsing.
break
fi
else
#
line=${line:i} # take command starting from found index
line=${line%% *} # trim arguments
procs+=($line)
fi
done
if ((i == -1)); then
# Regular axo command= parsing
for line in "${psout[@]}"; do
if [[ $line =~ ^[[(](.+)[])]$ ]]; then
procs+=(${BASH_REMATCH[1]})
else
line=${line%% *} # trim arguments
line=${line##@(*/|-)} # trim leading path and -
procs+=($line)
fi
done
fi
fi
COMPREPLY=($(compgen -X "<defunct>" -W '${procs[@]}' -- "$cur"))
}
fi
# This function completes on user IDs
#
_uids()
{
if type getent &>/dev/null; then
COMPREPLY=($(compgen -W '$(getent passwd | cut -d: -f3)' -- "$cur"))
elif type perl &>/dev/null; then
COMPREPLY=($(compgen -W '$(perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"')' -- "$cur"))
else
# make do with /etc/passwd
COMPREPLY=($(compgen -W '$(cut -d: -f3 /etc/passwd)' -- "$cur"))
fi
}
# This function completes on group IDs
#
_gids()
{
if type getent &>/dev/null; then
COMPREPLY=($(compgen -W '$(getent group | cut -d: -f3)' -- "$cur"))
elif type perl &>/dev/null; then
COMPREPLY=($(compgen -W '$(perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"')' -- "$cur"))
else
# make do with /etc/group
COMPREPLY=($(compgen -W '$(cut -d: -f3 /etc/group)' -- "$cur"))
fi
}
# Glob for matching various backup files.
#
_backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))'
# Complete on xinetd services
#
_xinetd_services()
{
local xinetddir=${BASHCOMP_XINETDDIR:-/etc/xinetd.d}
if [[ -d $xinetddir ]]; then
local IFS=$' \t\n' reset=$(shopt -p nullglob)
shopt -s nullglob
local -a svcs=($(printf '%s\n' $xinetddir/!($_backup_glob)))
$reset
((!${#svcs[@]})) ||
COMPREPLY+=($(compgen -W '${svcs[@]#$xinetddir/}' -- "${cur-}"))
fi
}
# This function completes on services
#
_services()
{
local sysvdirs
_sysvdirs
local IFS=$' \t\n' reset=$(shopt -p nullglob)
shopt -s nullglob
COMPREPLY=(
$(printf '%s\n' ${sysvdirs[0]}/!($_backup_glob|functions|README)))
$reset
COMPREPLY+=($({
systemctl list-units --full --all ||
systemctl list-unit-files
} 2>/dev/null |
awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }'))
if [[ -x /sbin/upstart-udev-bridge ]]; then
COMPREPLY+=($(initctl list 2>/dev/null | cut -d' ' -f1))
fi
COMPREPLY=($(compgen -W '${COMPREPLY[@]#${sysvdirs[0]}/}' -- "$cur"))
}
# This completes on a list of all available service scripts for the
# 'service' command and/or the SysV init.d directory, followed by
# that script's available commands
#
_service()
{
local cur prev words cword
_init_completion || return
# don't complete past 2nd token
((cword > 2)) && return
if [[ $cword -eq 1 && $prev == ?(*/)service ]]; then
_services
[[ -e /etc/mandrake-release ]] && _xinetd_services
else
local sysvdirs
_sysvdirs
COMPREPLY=($(compgen -W '`command sed -e "y/|/ /" \
-ne "s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p" \
${sysvdirs[0]}/${prev##*/} 2>/dev/null` start stop' -- "$cur"))
fi
} &&
complete -F _service service
_sysvdirs
for svcdir in "${sysvdirs[@]}"; do
for svc in $svcdir/!($_backup_glob); do
[[ -x $svc ]] && complete -F _service $svc
done
done
unset svc svcdir sysvdirs
# This function completes on modules
#
_modules()
{
local modpath
modpath=/lib/modules/$1
COMPREPLY=($(compgen -W "$(command ls -RL $modpath 2>/dev/null |
command sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.[gx]z\)\{0,1\}$/\1/p')" -- "$cur"))
}
# This function completes on installed modules
#
_installed_modules()
{
COMPREPLY=($(compgen -W "$(PATH="$PATH:/sbin" lsmod |
awk '{if (NR != 1) print $1}')" -- "$1"))
}
# This function completes on user or user:group format; as for chown and cpio.
#
# The : must be added manually; it will only complete usernames initially.
# The legacy user.group format is not supported.
#
# @param $1 If -u, only return users/groups the user has access to in
# context of current completion.
_usergroup()
{
if [[ $cur == *\\\\* || $cur == *:*:* ]]; then
# Give up early on if something seems horribly wrong.
return
elif [[ $cur == *\\:* ]]; then
# Completing group after 'user\:gr<TAB>'.
# Reply with a list of groups prefixed with 'user:', readline will
# escape to the colon.
local prefix
prefix=${cur%%*([^:])}
prefix=${prefix//\\/}
local mycur="${cur#*[:]}"
if [[ ${1-} == -u ]]; then
_allowed_groups "$mycur"
else
local IFS=$'\n'
COMPREPLY=($(compgen -g -- "$mycur"))
fi
COMPREPLY=($(compgen -P "$prefix" -W "${COMPREPLY[@]}"))
elif [[ $cur == *:* ]]; then
# Completing group after 'user:gr<TAB>'.
# Reply with a list of unprefixed groups since readline with split on :
# and only replace the 'gr' part
local mycur="${cur#*:}"
if [[ ${1-} == -u ]]; then
_allowed_groups "$mycur"
else
local IFS=$'\n'
COMPREPLY=($(compgen -g -- "$mycur"))
fi
else
# Completing a partial 'usernam<TAB>'.
#
# Don't suffix with a : because readline will escape it and add a
# slash. It's better to complete into 'chown username ' than 'chown
# username\:'.
if [[ ${1-} == -u ]]; then
_allowed_users "$cur"
else
local IFS=$'\n'
COMPREPLY=($(compgen -u -- "$cur"))
fi
fi
}
_allowed_users()
{
if _complete_as_root; then
local IFS=$'\n'
COMPREPLY=($(compgen -u -- "${1:-$cur}"))
else
local IFS=$'\n '
COMPREPLY=($(compgen -W \
"$(id -un 2>/dev/null || whoami 2>/dev/null)" -- "${1:-$cur}"))
fi
}
_allowed_groups()
{
if _complete_as_root; then
local IFS=$'\n'
COMPREPLY=($(compgen -g -- "$1"))
else
local IFS=$'\n '
COMPREPLY=($(compgen -W \
"$(id -Gn 2>/dev/null || groups 2>/dev/null)" -- "$1"))
fi
}
# This function completes on valid shells
#
_shells()
{
local shell rest
while read -r shell rest; do
[[ $shell == /* && $shell == "$cur"* ]] && COMPREPLY+=($shell)
done 2>/dev/null </etc/shells
}
# This function completes on valid filesystem types
#
_fstypes()
{
local fss
if [[ -e /proc/filesystems ]]; then
# Linux
fss="$(cut -d$'\t' -f2 /proc/filesystems)
$(awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null)"
else
# Generic
fss="$(awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null)
$(awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null)
$(awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null)
$(awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null)
$([[ -d /etc/fs ]] && command ls /etc/fs)"
fi
[[ -n $fss ]] && COMPREPLY+=($(compgen -W "$fss" -- "$cur"))
}
# Get real command.
# - arg: $1 Command
# - stdout: Filename of command in PATH with possible symbolic links resolved.
# Empty string if command not found.
# - return: True (0) if command found, False (> 0) if not.
_realcommand()
{
type -P "$1" >/dev/null && {
if type -p realpath >/dev/null; then
realpath "$(type -P "$1")"
elif type -p greadlink >/dev/null; then
greadlink -f "$(type -P "$1")"
elif type -p readlink >/dev/null; then
readlink -f "$(type -P "$1")"
else
type -P "$1"
fi
}
}
# This function returns the first argument, excluding options
# @param $1 chars Characters out of $COMP_WORDBREAKS which should
# NOT be considered word breaks. See __reassemble_comp_words_by_ref.
_get_first_arg()
{
local i
arg=
for ((i = 1; i < COMP_CWORD; i++)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
arg=${COMP_WORDS[i]}
break
fi
done
}
# This function counts the number of args, excluding options
# @param $1 chars Characters out of $COMP_WORDBREAKS which should
# NOT be considered word breaks. See __reassemble_comp_words_by_ref.
# @param $2 glob Options whose following argument should not be counted
# @param $3 glob Options that should be counted as args
_count_args()
{
local i cword words
__reassemble_comp_words_by_ref "${1-}" words cword
args=1
for ((i = 1; i < cword; i++)); do
# shellcheck disable=SC2053
if [[ ${words[i]} != -* && ${words[i - 1]} != ${2-} || \
${words[i]} == ${3-} ]]; then
((args++))
fi
done
}
# This function completes on PCI IDs
#
_pci_ids()
{
COMPREPLY+=($(compgen -W \
"$(PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur"))
}
# This function completes on USB IDs
#
_usb_ids()
{
COMPREPLY+=($(compgen -W \
"$(PATH="$PATH:/sbin" lsusb | awk '{print $6}')" -- "$cur"))
}
# CD device names
_cd_devices()
{
COMPREPLY+=($(compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}"))
}
# DVD device names
_dvd_devices()
{
COMPREPLY+=($(compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}"))
}
# TERM environment variable values
_terms()
{
COMPREPLY+=($(compgen -W "$({
command sed -ne 's/^\([^[:space:]#|]\{2,\}\)|.*/\1/p' /etc/termcap
{
toe -a || toe
} | awk '{ print $1 }'
find /{etc,lib,usr/lib,usr/share}/terminfo/? -type f -maxdepth 1 |
awk -F/ '{ print $NF }'
} 2>/dev/null)" -- "$cur"))
}
_bashcomp_try_faketty()
{
if type unbuffer &>/dev/null; then
unbuffer -p "$@"
elif script --version 2>&1 | command grep -qF util-linux; then
# BSD and Solaris "script" do not seem to have required features
script -qaefc "$*" /dev/null
else
"$@" # no can do, fallback
fi
}
# a little help for FreeBSD ports users
[[ $OSTYPE == *freebsd* ]] && complete -W 'index search fetch fetch-list
extract patch configure build install reinstall deinstall clean
clean-depends kernel buildworld' make
# This function provides simple user@host completion
#
_user_at_host()
{
local cur prev words cword
_init_completion -n : || return
if [[ $cur == *@* ]]; then
_known_hosts_real "$cur"
else
COMPREPLY=($(compgen -u -S @ -- "$cur"))
compopt -o nospace
fi
}
shopt -u hostcomplete && complete -F _user_at_host talk ytalk finger
# NOTE: Using this function as a helper function is deprecated. Use
# `_known_hosts_real' instead.
_known_hosts()
{
local cur prev words cword
_init_completion -n : || return
# NOTE: Using `_known_hosts' as a helper function and passing options
# to `_known_hosts' is deprecated: Use `_known_hosts_real' instead.
local options
[[ ${1-} == -a || ${2-} == -a ]] && options=-a
[[ ${1-} == -c || ${2-} == -c ]] && options+=" -c"
_known_hosts_real ${options-} -- "$cur"
} # _known_hosts()
# Helper function to locate ssh included files in configs
# This function looks for the "Include" keyword in ssh config files and
# includes them recursively, adding each result to the config variable.
_included_ssh_config_files()
{
(($# < 1)) &&
echo "bash_completion: $FUNCNAME: missing mandatory argument CONFIG" >&2
local configfile i f
configfile=$1
local reset=$(shopt -po noglob)
set -o noglob
local included=($(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${configfile}"))
$reset
[[ ${included-} ]] || return
for i in "${included[@]}"; do
# Check the origin of $configfile to complete relative included paths on included
# files according to ssh_config(5):
# "[...] Files without absolute paths are assumed to be in ~/.ssh if included in a user
# configuration file or /etc/ssh if included from the system configuration file.[...]"
if ! [[ $i =~ ^\~.*|^\/.* ]]; then
if [[ $configfile =~ ^\/etc\/ssh.* ]]; then
i="/etc/ssh/$i"
else
i="$HOME/.ssh/$i"
fi
fi
__expand_tilde_by_ref i
# In case the expanded variable contains multiple paths
set +o noglob
for f in $i; do
if [[ -r $f ]]; then
config+=("$f")
# The Included file is processed to look for Included files in itself
_included_ssh_config_files $f
fi
done
$reset
done
} # _included_ssh_config_files()
# Helper function for completing _known_hosts.
# This function performs host completion based on ssh's config and known_hosts
# files, as well as hostnames reported by avahi-browse if
# COMP_KNOWN_HOSTS_WITH_AVAHI is set to a non-empty value. Also hosts from
# HOSTFILE (compgen -A hostname) are added, unless
# COMP_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value.
# Usage: _known_hosts_real [OPTIONS] CWORD
# Options: -a Use aliases from ssh config files
# -c Use `:' suffix
# -F configfile Use `configfile' for configuration settings
# -p PREFIX Use PREFIX
# -4 Filter IPv6 addresses from results
# -6 Filter IPv4 addresses from results
# Return: Completions, starting with CWORD, are added to COMPREPLY[]
_known_hosts_real()
{
local configfile flag prefix="" ifs=$IFS
local cur suffix="" aliases i host ipv4 ipv6
local -a kh tmpkh=() khd=() config=()
# TODO remove trailing %foo from entries
local OPTIND=1
while getopts "ac46F:p:" flag "$@"; do
case $flag in
a) aliases='yes' ;;
c) suffix=':' ;;
F) configfile=$OPTARG ;;
p) prefix=$OPTARG ;;
4) ipv4=1 ;;
6) ipv6=1 ;;
*)
echo "bash_completion: $FUNCNAME: usage error" >&2
return 1
;;
esac
done
if (($# < OPTIND)); then
echo "bash_completion: $FUNCNAME: missing mandatory argument CWORD" >&2
return 1
fi
cur=${!OPTIND}
((OPTIND += 1))
if (($# >= OPTIND)); then
echo "bash_completion: $FUNCNAME($*): unprocessed arguments:" \
"$(while (($# >= OPTIND)); do
printf '%s ' ${!OPTIND}
shift
done)" >&2
return 1
fi
[[ $cur == *@* ]] && prefix=$prefix${cur%@*}@ && cur=${cur#*@}
kh=()
# ssh config files
if [[ -v configfile ]]; then
[[ -r $configfile ]] && config+=("$configfile")
else
for i in /etc/ssh/ssh_config ~/.ssh/config ~/.ssh2/config; do
[[ -r $i ]] && config+=("$i")
done
fi
local reset=$(shopt -po noglob)
set -o noglob
# "Include" keyword in ssh config files
if ((${#config[@]} > 0)); then
for i in "${config[@]}"; do
_included_ssh_config_files "$i"
done
fi
# Known hosts files from configs
if ((${#config[@]} > 0)); then
local IFS=$'\n'
# expand paths (if present) to global and user known hosts files
# TODO(?): try to make known hosts files with more than one consecutive
# spaces in their name work (watch out for ~ expansion
# breakage! Alioth#311595)
tmpkh=($(awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t]+", "") { print $0 }' "${config[@]}" | sort -u))
IFS=$ifs
fi
if ((${#tmpkh[@]} != 0)); then
local j
for i in "${tmpkh[@]}"; do
# First deal with quoted entries...
while [[ $i =~ ^([^\"]*)\"([^\"]*)\"(.*)$ ]]; do
i=${BASH_REMATCH[1]}${BASH_REMATCH[3]}
j=${BASH_REMATCH[2]}
__expand_tilde_by_ref j # Eval/expand possible `~' or `~user'
[[ -r $j ]] && kh+=("$j")
done
# ...and then the rest.
for j in $i; do
__expand_tilde_by_ref j # Eval/expand possible `~' or `~user'
[[ -r $j ]] && kh+=("$j")
done
done
fi
if [[ ! -v configfile ]]; then
# Global and user known_hosts files
for i in /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 \
/etc/known_hosts /etc/known_hosts2 ~/.ssh/known_hosts \
~/.ssh/known_hosts2; do
[[ -r $i ]] && kh+=("$i")
done
for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do
[[ -d $i ]] && khd+=("$i"/*pub)
done
fi
# If we have known_hosts files to use
if ((${#kh[@]} + ${#khd[@]} > 0)); then
if ((${#kh[@]} > 0)); then
# https://man.openbsd.org/sshd.8#SSH_KNOWN_HOSTS_FILE_FORMAT
for i in "${kh[@]}"; do
while read -ra tmpkh; do
((${#tmpkh[@]} == 0)) && continue
set -- "${tmpkh[@]}"
# Skip entries starting with | (hashed) and # (comment)
[[ $1 == [\|\#]* ]] && continue
# Ignore leading @foo (markers)
[[ $1 == @* ]] && shift
# Split entry on commas
local IFS=,
for host in $1; do
# Skip hosts containing wildcards
[[ $host == *[*?]* ]] && continue
# Remove leading [
host="${host#[}"
# Remove trailing ] + optional :port
host="${host%]?(:+([0-9]))}"
# Add host to candidates
COMPREPLY+=($host)
done
IFS=$ifs
done <"$i"
done
COMPREPLY=($(compgen -W '${COMPREPLY[@]}' -- "$cur"))
fi
if ((${#khd[@]} > 0)); then
# Needs to look for files called
# .../.ssh2/key_22_<hostname>.pub
# dont fork any processes, because in a cluster environment,
# there can be hundreds of hostkeys
for i in "${khd[@]}"; do
if [[ $i == *key_22_$cur*.pub && -r $i ]]; then
host=${i/#*key_22_/}
host=${host/%.pub/}
COMPREPLY+=($host)
fi
done
fi
# apply suffix and prefix
for i in ${!COMPREPLY[*]}; do
COMPREPLY[i]=$prefix${COMPREPLY[i]}$suffix
done
fi
# append any available aliases from ssh config files
if [[ ${#config[@]} -gt 0 && -v aliases ]]; then
local -a hosts=($(command sed -ne 's/^[[:blank:]]*[Hh][Oo][Ss][Tt][[:blank:]]\(.*\)$/\1/p' "${config[@]}"))
if ((${#hosts[@]} != 0)); then
COMPREPLY+=($(compgen -P "$prefix" \
-S "$suffix" -W '${hosts[@]%%[*?%]*}' -X '\!*' -- "$cur"))
fi
fi
# Add hosts reported by avahi-browse, if desired and it's available.
if [[ ${COMP_KNOWN_HOSTS_WITH_AVAHI-} ]] &&
type avahi-browse &>/dev/null; then
# The original call to avahi-browse also had "-k", to avoid lookups
# into avahi's services DB. We don't need the name of the service, and
# if it contains ";", it may mistify the result. But on Gentoo (at
# least), -k wasn't available (even if mentioned in the manpage) some
# time ago, so...
COMPREPLY+=($(compgen -P "$prefix" -S "$suffix" -W \
"$(avahi-browse -cpr _workstation._tcp 2>/dev/null |
awk -F';' '/^=/ { print $7 }' | sort -u)" -- "$cur"))
fi
# Add hosts reported by ruptime.
if type ruptime &>/dev/null; then
COMPREPLY+=($(compgen -W \
"$(ruptime 2>/dev/null | awk '!/^ruptime:/ { print $1 }')" \
-- "$cur"))
fi
# Add results of normal hostname completion, unless
# `COMP_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value.
if [[ -n ${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1} ]]; then
COMPREPLY+=(
$(compgen -A hostname -P "$prefix" -S "$suffix" -- "$cur"))
fi
$reset
if [[ -v ipv4 ]]; then
COMPREPLY=("${COMPREPLY[@]/*:*$suffix/}")
fi
if [[ -v ipv6 ]]; then
COMPREPLY=("${COMPREPLY[@]/+([0-9]).+([0-9]).+([0-9]).+([0-9])$suffix/}")
fi
if [[ -v ipv4 || -v ipv6 ]]; then
for i in "${!COMPREPLY[@]}"; do
[[ ${COMPREPLY[i]} ]] || unset -v "COMPREPLY[i]"
done
fi
__ltrim_colon_completions "$prefix$cur"
} # _known_hosts_real()
complete -F _known_hosts traceroute traceroute6 \
fping fping6 telnet rsh rlogin ftp dig mtr ssh-installkeys showmount
# This meta-cd function observes the CDPATH variable, so that cd additionally
# completes on directories under those specified in CDPATH.
#
_cd()
{
local cur prev words cword
_init_completion || return
local IFS=$'\n' i j k
compopt -o filenames
# Use standard dir completion if no CDPATH or parameter starts with /,
# ./ or ../
if [[ -z ${CDPATH:-} || $cur == ?(.)?(.)/* ]]; then
_filedir -d
return
fi
local -r mark_dirs=$(_rl_enabled mark-directories && echo y)
local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y)
# we have a CDPATH, so loop on its contents
for i in ${CDPATH//:/$'\n'}; do
# create an array of matched subdirs
k="${#COMPREPLY[@]}"
for j in $(compgen -d -- $i/$cur); do
if [[ ($mark_symdirs && -L $j || $mark_dirs && ! -L $j) && ! -d ${j#$i/} ]]; then
j+="/"
fi
COMPREPLY[k++]=${j#$i/}
done
done
_filedir -d
if ((${#COMPREPLY[@]} == 1)); then
i=${COMPREPLY[0]}
if [[ $i == "$cur" && $i != "*/" ]]; then
COMPREPLY[0]="${i}/"
fi
fi
return
}
if shopt -q cdable_vars; then
complete -v -F _cd -o nospace cd pushd
else
complete -F _cd -o nospace cd pushd
fi
# A _command_offset wrapper function for use when the offset is unknown.
# Only intended to be used as a completion function directly associated
# with a command, not to be invoked from within other completion functions.
#
_command()
{
local offset i
# find actual offset, as position of the first non-option
offset=1
for ((i = 1; i <= COMP_CWORD; i++)); do
if [[ ${COMP_WORDS[i]} != -* ]]; then
offset=$i
break
fi
done
_command_offset $offset
}
# 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.
#
_command_offset()
{
# rewrite current completion context before invoking
# actual command completion
# find new first word position, then
# rewrite COMP_LINE and adjust COMP_POINT
local word_offset=$1 i j
for ((i = 0; i < word_offset; i++)); do
for ((j = 0; j <= ${#COMP_LINE}; j++)); do
[[ $COMP_LINE == "${COMP_WORDS[i]}"* ]] && break
COMP_LINE=${COMP_LINE:1}
((COMP_POINT--))
done
COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"}
((COMP_POINT -= ${#COMP_WORDS[i]}))
done
# shift COMP_WORDS elements and adjust COMP_CWORD
for ((i = 0; i <= COMP_CWORD - word_offset; i++)); do
COMP_WORDS[i]=${COMP_WORDS[i + word_offset]}
done
for ((i; i <= COMP_CWORD; i++)); do
unset 'COMP_WORDS[i]'
done
((COMP_CWORD -= word_offset))
COMPREPLY=()
local cur
_get_comp_words_by_ref cur
if ((COMP_CWORD == 0)); then
local IFS=$'\n'
compopt -o filenames
COMPREPLY=($(compgen -d -c -- "$cur"))
else
local cmd=${COMP_WORDS[0]} compcmd=${COMP_WORDS[0]}
local cspec=$(complete -p $cmd 2>/dev/null)
# If we have no completion for $cmd yet, see if we have for basename
if [[ ! $cspec && $cmd == */* ]]; then
cspec=$(complete -p ${cmd##*/} 2>/dev/null)
[[ $cspec ]] && compcmd=${cmd##*/}
fi
# If still nothing, just load it for the basename
if [[ ! $cspec ]]; then
compcmd=${cmd##*/}
_completion_loader $compcmd
cspec=$(complete -p $compcmd 2>/dev/null)
fi
if [[ -n $cspec ]]; then
if [[ ${cspec#* -F } != "$cspec" ]]; then
# complete -F <function>
# get function name
local func=${cspec#*-F }
func=${func%% *}
if ((${#COMP_WORDS[@]} >= 2)); then
$func $cmd "${COMP_WORDS[-1]}" "${COMP_WORDS[-2]}"
else
$func $cmd "${COMP_WORDS[-1]}"
fi
# restore initial compopts
local opt
while [[ $cspec == *" -o "* ]]; do
# FIXME: should we take "+o opt" into account?
cspec=${cspec#*-o }
opt=${cspec%% *}
compopt -o $opt
cspec=${cspec#$opt}
done
else
cspec=${cspec#complete}
cspec=${cspec%%$compcmd}
COMPREPLY=($(eval compgen "$cspec" -- '$cur'))
fi
elif ((${#COMPREPLY[@]} == 0)); then
# XXX will probably never happen as long as completion loader loads
# *something* for every command thrown at it ($cspec != empty)
_minimal
fi
fi
}
complete -F _command aoss command "do" else eval exec ltrace nice nohup padsp \
"then" time tsocks vsound xargs
_root_command()
{
local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
local root_command=$1
_command
}
complete -F _root_command fakeroot gksu gksudo kdesudo really
# Return true if the completion should be treated as running as root
_complete_as_root()
{
[[ $EUID -eq 0 || ${root_command:-} ]]
}
_longopt()
{
local cur prev words cword split
_init_completion -s || return
case "${prev,,}" in
--help | --usage | --version)
return
;;
--!(no-*)dir*)
_filedir -d
return
;;
--!(no-*)@(file|path)*)
_filedir
return
;;
--+([-a-z0-9_]))
local argtype=$(LC_ALL=C $1 --help 2>&1 | command sed -ne \
"s|.*$prev\[\{0,1\}=[<[]\{0,1\}\([-A-Za-z0-9_]\{1,\}\).*|\1|p")
case ${argtype,,} in
*dir*)
_filedir -d
return
;;
*file* | *path*)
_filedir
return
;;
esac
;;
esac
$split && return
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W "$(LC_ALL=C $1 --help 2>&1 |
while read -r line; do
[[ $line =~ --[A-Za-z0-9]+([-_][A-Za-z0-9]+)*=? ]] &&
printf '%s\n' ${BASH_REMATCH[0]}
done)" -- "$cur"))
[[ ${COMPREPLY-} == *= ]] && compopt -o nospace
elif [[ $1 == *@(rmdir|chroot) ]]; then
_filedir -d
else
[[ $1 == *mkdir ]] && compopt -o nospace
_filedir
fi
}
# makeinfo and texi2dvi are defined elsewhere.
complete -F _longopt a2ps awk base64 bash bc bison cat chroot colordiff cp \
csplit cut date df diff dir du enscript env expand fmt fold gperf \
grep grub head irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \
mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \
sed seq sha{,1,224,256,384,512}sum shar sort split strip sum tac tail tee \
texindex touch tr uname unexpand uniq units vdir wc who
declare -Ag _xspecs
_filedir_xspec()
{
local cur prev words cword
_init_completion || return
_tilde "$cur" || return
local IFS=$'\n' xspec=${_xspecs[${1##*/}]} tmp
local -a toks
toks=($(
compgen -d -- "$(quote_readline "$cur")" | {
while read -r tmp; do
printf '%s\n' $tmp
done
}
))
# Munge xspec to contain uppercase version too
# https://lists.gnu.org/archive/html/bug-bash/2010-09/msg00036.html
# news://news.gmane.io/4C940E1C.1010304@case.edu
eval xspec="${xspec}"
local matchop=!
if [[ $xspec == !* ]]; then
xspec=${xspec#!}
matchop=@
fi
xspec="$matchop($xspec|${xspec^^})"
toks+=($(
eval compgen -f -X "'!$xspec'" -- '$(quote_readline "$cur")' | {
while read -r tmp; do
[[ -n $tmp ]] && printf '%s\n' $tmp
done
}
))
# Try without filter if it failed to produce anything and configured to
[[ -n ${COMP_FILEDIR_FALLBACK:-} && ${#toks[@]} -lt 1 ]] && {
local reset=$(shopt -po noglob)
set -o noglob
toks+=($(compgen -f -- "$(quote_readline "$cur")"))
IFS=' '
$reset
IFS=$'\n'
}
if ((${#toks[@]} != 0)); then
compopt -o filenames
COMPREPLY=("${toks[@]}")
fi
}
_install_xspec()
{
local xspec=$1 cmd
shift
for cmd in "$@"; do
_xspecs[$cmd]=$xspec
done
}
# bzcmp, bzdiff, bz*grep, bzless, bzmore intentionally not here, see Debian: #455510
_install_xspec '!*.?(t)bz?(2)' bunzip2 bzcat pbunzip2 pbzcat lbunzip2 lbzcat
_install_xspec '!*.@(zip|[aegjswx]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|epub|apk|aab|ipa|do[ct][xm]|p[op]t[mx]|xl[st][xm]|pyz|whl)' unzip zipinfo
_install_xspec '*.Z' compress znew
# zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510
_install_xspec '!*.@(Z|[gGd]z|t[ag]z)' gunzip zcat
_install_xspec '!*.@(Z|[gGdz]z|t[ag]z)' unpigz
_install_xspec '!*.Z' uncompress
# lzcmp, lzdiff intentionally not here, see Debian: #455510
_install_xspec '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma
_install_xspec '!*.@(?(t)xz|tlz|lzma)' unxz xzcat
_install_xspec '!*.lrz' lrunzip
_install_xspec '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee
_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|svg)' qiv
_install_xspec '!*.@(gif|jp?(e)g?(2)|j2[ck]|jp[2f]|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|?(e)ps)' xv
_install_xspec '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview
_install_xspec '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi
_install_xspec '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx
_install_xspec '!*.[pf]df' acroread gpdf
_install_xspec '!*.@(pdf|fdf)?(.@(gz|GZ|bz2|BZ2|Z))' xpdf
_install_xspec '!*.@(?(e)ps|pdf)' kpdf
_install_xspec '!*.@(okular|@(?(e|x)ps|?(E|X)PS|[pf]df|[PF]DF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb?(2)|FB?(2)|mobi|MOBI|g3|G3|chm|CHM)?(.?(gz|GZ|bz2|BZ2|xz|XZ)))' okular
_install_xspec '!*.pdf' epdfview pdfunite
_install_xspec '!*.@(cb[rz7t]|djv?(u)|?(e)ps|pdf)' zathura
_install_xspec '!*.@(?(e)ps|pdf)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr
_install_xspec '!*.texi*' makeinfo texi2html
_install_xspec '!*.@(?(la)tex|texi|dtx|ins|ltx|dbj)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi xetex xelatex luatex lualatex
_install_xspec '!*.mp3' mpg123 mpg321 madplay
_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmvx]|OG[AGMVX]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' xine aaxine fbxine
_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmvx]|OG[AGMVX]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM|iso|ISO)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' kaffeine dragon totem
_install_xspec '!*.@(avi|asf|wmv)' aviplay
_install_xspec '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay
_install_xspec '!*.@(mpg|mpeg|avi|mov|qt)' xanim
_install_xspec '!*.@(og[ag]|m3u|flac|spx)' ogg123
_install_xspec '!*.@(mp3|og[ag]|pls|m3u)' gqmpeg freeamp
_install_xspec '!*.fig' xfig
_install_xspec '!*.@(mid?(i)|cmf)' playmidi
_install_xspec '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity
_install_xspec '!*.@(669|abc|am[fs]|d[bs]m|dmf|far|it|mdl|m[eo]d|mid?(i)|mt[2m]|oct|okt?(a)|p[st]m|s[3t]m|ult|umx|wav|xm)' modplugplay modplug123
_install_xspec '*.@([ao]|so|so.!(conf|*/*)|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite
_install_xspec '!*.@(zip|z|gz|tgz)' bzme
# konqueror not here on purpose, it's more than a web/html browser
_install_xspec '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx galeon dillo elinks amaya epiphany
_install_xspec '!*.@(sxw|stw|sxg|sgl|doc?([mx])|dot?([mx])|rtf|txt|htm|html|?(f)odt|ott|odm|pdf)' oowriter lowriter
_install_xspec '!*.@(sxi|sti|pps?(x)|ppt?([mx])|pot?([mx])|?(f)odp|otp)' ooimpress loimpress
_install_xspec '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|?(f)ods|ots)' oocalc localc
_install_xspec '!*.@(sxd|std|sda|sdd|?(f)odg|otg)' oodraw lodraw
_install_xspec '!*.@(sxm|smf|mml|odf)' oomath lomath
_install_xspec '!*.odb' oobase lobase
_install_xspec '!*.[rs]pm' rpm2cpio
_install_xspec '!*.aux' bibtex
_install_xspec '!*.po' poedit gtranslator kbabel lokalize
_install_xspec '!*.@([Pp][Rr][Gg]|[Cc][Ll][Pp])' harbour gharbour hbpp
_install_xspec '!*.[Hh][Rr][Bb]' hbrun
_install_xspec '!*.ly' lilypond ly2dvi
_install_xspec '!*.@(dif?(f)|?(d)patch)?(.@([gx]z|bz2|lzma))' cdiff
_install_xspec '!@(*.@(ks|jks|jceks|p12|pfx|bks|ubr|gkr|cer|crt|cert|p7b|pkipath|pem|p10|csr|crl)|cacerts)' portecle
_install_xspec '!*.@(mp[234c]|og[ag]|@(fl|a)ac|m4[abp]|spx|tta|w?(a)v|wma|aif?(f)|asf|ape)' kid3 kid3-qt
unset -f _install_xspec
# Minimal completion to use as fallback in _completion_loader.
_minimal()
{
local cur prev words cword split
_init_completion -s || return
$split && return
_filedir
}
# Complete the empty string to allow completion of '>', '>>', and '<' on < 4.3
# https://lists.gnu.org/archive/html/bug-bash/2012-01/msg00045.html
complete -F _minimal ''
__load_completion()
{
local -a dirs=(${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions)
local ifs=$IFS IFS=: dir cmd="${1##*/}" compfile
[[ -n $cmd ]] || return 1
for dir in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do
dirs+=($dir/bash-completion/completions)
done
IFS=$ifs
if [[ $BASH_SOURCE == */* ]]; then
dirs+=("${BASH_SOURCE%/*}/completions")
else
dirs+=(./completions)
fi
local backslash=
if [[ $cmd == \\* ]]; then
cmd="${cmd:1}"
# If we already have a completion for the "real" command, use it
$(complete -p "$cmd" 2>/dev/null || echo false) "\\$cmd" && return 0
backslash=\\
fi
for dir in "${dirs[@]}"; do
[[ -d $dir ]] || continue
for compfile in "$cmd" "$cmd.bash" "_$cmd"; do
compfile="$dir/$compfile"
# Avoid trying to source dirs; https://bugzilla.redhat.com/903540
if [[ -f $compfile ]] && . "$compfile" &>/dev/null; then
[[ $backslash ]] && $(complete -p "$cmd") "\\$cmd"
return 0
fi
done
done
# Look up simple "xspec" completions
[[ -v _xspecs[$cmd] ]] &&
complete -F _filedir_xspec "$cmd" "$backslash$cmd" && return 0
return 1
}
# set up dynamic completion loading
_completion_loader()
{
# $1=_EmptycmD_ already for empty cmds in bash 4.3, set to it for earlier
local cmd="${1:-_EmptycmD_}"
__load_completion "$cmd" && return 124
# Need to define *something*, otherwise there will be no completion at all.
complete -F _minimal -- "$cmd" && return 124
} &&
complete -D -F _completion_loader
# Function for loading and calling functions from dynamically loaded
# completion files that may not have been sourced yet.
# @param $1 completion file to load function from in case it is missing
# @param $2... function and its arguments
_xfunc()
{
set -- "$@"
local srcfile=$1
shift
declare -F $1 &>/dev/null || __load_completion "$srcfile"
"$@"
}
# source compat completion directory definitions
compat_dir=${BASH_COMPLETION_COMPAT_DIR:-/etc/bash_completion.d}
if [[ -d $compat_dir && -r $compat_dir && -x $compat_dir ]]; then
for i in "$compat_dir"/*; do
[[ ${i##*/} != @($_backup_glob|Makefile*|$_blacklist_glob) && -f \
$i && -r $i ]] && . "$i"
done
fi
unset compat_dir i _blacklist_glob
# source user completion file
user_completion=${BASH_COMPLETION_USER_FILE:-~/.bash_completion}
[[ ${BASH_SOURCE[0]} != "$user_completion" && -r $user_completion && -f $user_completion ]] &&
. $user_completion
unset user_completion
unset -f have
unset have
set $BASH_COMPLETION_ORIGINAL_V_VALUE
unset BASH_COMPLETION_ORIGINAL_V_VALUE
# ex: filetype=sh
# ssh(1) completion -*- shell-script -*-
_ssh_queries()
{
COMPREPLY+=($(compgen -W \
"cipher cipher-auth help mac kex key key-cert key-plain key-sig
protocol-version compression sig
ciphers macs kexalgorithms pubkeyacceptedkeytypes
hostkeyalgorithms hostbasedkeytypes hostbasedacceptedkeytypes" \
-- "${cur,,}"))
}
_ssh_query()
{
${1:-ssh} -Q $2 2>/dev/null
}
_ssh_ciphers()
{
local ciphers='$(_ssh_query "$1" cipher)'
[[ $ciphers ]] || ciphers="3des-cbc aes128-cbc aes192-cbc aes256-cbc
aes128-ctr aes192-ctr aes256-ctr arcfour128 arcfour256 arcfour
blowfish-cbc cast128-cbc"
COMPREPLY+=($(compgen -W "$ciphers" -- "$cur"))
}
_ssh_macs()
{
local macs='$(_ssh_query "$1" mac)'
[[ $macs ]] || macs="hmac-md5 hmac-sha1 umac-64@openssh.com hmac-ripemd160
hmac-sha1-96 hmac-md5-96"
COMPREPLY+=($(compgen -W "$macs" -- "$cur"))
}
_ssh_options()
{
local opts=(
AddKeysToAgent AddressFamily BatchMode BindAddress CanonicalDomains
CanonicalizeFallbackLocal CanonicalizeHostname CanonicalizeMaxDots
CanonicalizePermittedCNAMEs CASignatureAlgorithms CertificateFile
ChallengeResponseAuthentication CheckHostIP Ciphers ClearAllForwardings
Compression ConnectionAttempts ConnectTimeout ControlMaster ControlPath
ControlPersist DynamicForward EnableSSHKeysign EscapeChar
ExitOnForwardFailure FingerprintHash ForwardAgent ForwardX11
ForwardX11Timeout ForwardX11Trusted GatewayPorts GlobalKnownHostsFile
GSSAPIAuthentication GSSAPIClientIdentity GSSAPIDelegateCredentials
GSSAPIKeyExchange GSSAPIRenewalForcesRekey GSSAPIServerIdentity
GSSAPITrustDns HashKnownHosts Host HostbasedAuthentication
HostbasedKeyTypes HostKeyAlgorithms HostKeyAlias HostName
IdentitiesOnly IdentityAgent IdentityFile IgnoreUnknown Include IPQoS
KbdInteractiveAuthentication KbdInteractiveDevices KexAlgorithms
LocalCommand LocalForward LogLevel MACs
NoHostAuthenticationForLocalhost NumberOfPasswordPrompts
PasswordAuthentication PermitLocalCommand PKCS11Provider Port
PreferredAuthentications ProxyCommand ProxyJump ProxyUseFdpass
PubkeyAcceptedKeyTypes PubkeyAuthentication RekeyLimit RemoteCommand
RemoteForward RequestTTY RevokedHostKeys SendEnv ServerAliveCountMax
ServerAliveInterval SmartcardDevice StreamLocalBindMask
StreamLocalBindUnlink StrictHostKeyChecking SyslogFacility TCPKeepAlive
Tunnel TunnelDevice UpdateHostKeys UsePrivilegedPort User
UserKnownHostsFile VerifyHostKeyDNS VisualHostKey XAuthLocation)
local protocols=$(_ssh_query "$1" protocol-version)
if [[ -z $protocols || $protocols == *1* ]]; then
opts+=(Cipher CompressionLevel Protocol RhostsRSAAuthentication
RSAAuthentication)
fi
compopt -o nospace
local IFS=$' \t\n' reset=$(shopt -p nocasematch)
shopt -s nocasematch
local option
COMPREPLY=($(for option in "${opts[@]}"; do
[[ $option == "$cur"* ]] && printf '%s=\n' "$option"
done))
$reset
}
# Complete a ssh suboption (like ForwardAgent=y<tab>)
# Two parameters: the string to complete including the equal sign, and
# the ssh executable to invoke (optional).
# Not all suboptions are completed.
# Doesn't handle comma-separated lists.
_ssh_suboption()
{
# Split into subopt and subval
local prev=${1%%=*} cur=${1#*=}
case ${prev,,} in
batchmode | canonicaldomains | canonicalizefallbacklocal | \
challengeresponseauthentication | checkhostip | \
clearallforwardings | controlpersist | compression | enablesshkeysign | \
exitonforwardfailure | forwardagent | forwardx11 | forwardx11trusted | \
gatewayports | gssapiauthentication | gssapikeyexchange | \
gssapidelegatecredentials | gssapirenewalforcesrekey | gssapitrustdns | \
hashknownhosts | hostbasedauthentication | identitiesonly | \
kbdinteractiveauthentication | kbdinteractivedevices | \
nohostauthenticationforlocalhost | passwordauthentication | permitlocalcommand | \
proxyusefdpass | pubkeyauthentication | rhostsrsaauthentication | \
rsaauthentication | streamlocalbindunlink | \
tcpkeepalive | useprivilegedport | visualhostkey)
COMPREPLY=($(compgen -W 'yes no' -- "$cur"))
;;
addkeystoagent)
COMPREPLY=($(compgen -W 'yes ask confirm no' -- "$cur"))
;;
addressfamily)
COMPREPLY=($(compgen -W 'any inet inet6' -- "$cur"))
;;
bindaddress)
_ip_addresses
;;
canonicalizehostname)
COMPREPLY=($(compgen -W 'yes no always' -- "$cur"))
;;
identityfile)
_ssh_identityfile
;;
*file | identityagent | include | controlpath | revokedhostkeys | xauthlocation)
_filedir
;;
casignaturealgorithms)
COMPREPLY=($(compgen -W '$(_ssh_query "$2" sig)' -- "$cur"))
;;
cipher)
COMPREPLY=($(compgen -W 'blowfish des 3des' -- "$cur"))
;;
ciphers)
_ssh_ciphers "$2"
;;
controlmaster)
COMPREPLY=($(compgen -W 'yes ask auto autoask no' -- "$cur"))
;;
compressionlevel)
COMPREPLY=($(compgen -W '{1..9}' -- "$cur"))
;;
fingerprinthash)
COMPREPLY=($(compgen -W 'md5 sha256' -- "$cur"))
;;
ipqos)
COMPREPLY=($(compgen -W 'af1{1..4} af2{2..3} af3{1..3} af4{1..3}
cs{0..7} ef lowdelay throughput reliability' -- "$cur"))
;;
hostbasedkeytypes | hostkeyalgorithms)
COMPREPLY=($(compgen -W '$(_ssh_query "$2" key)' -- "$cur"))
;;
kexalgorithms)
COMPREPLY=($(compgen -W '$(_ssh_query "$2" kex)' -- "$cur"))
;;
loglevel)
COMPREPLY=($(compgen -W 'QUIET FATAL ERROR INFO VERBOSE DEBUG{,1,2,3}' -- "$cur"))
;;
macs)
_ssh_macs "$2"
;;
pkcs11provider)
_filedir so
;;
preferredauthentications)
COMPREPLY=($(compgen -W 'gssapi-with-mic host-based publickey
keyboard-interactive password' -- "$cur"))
;;
protocol)
local protocols=($(_ssh_query "$2" protocol-version))
[[ $protocols ]] || protocols=(1 2)
if ((${#protocols[@]} > 1)); then
COMPREPLY=($(compgen -W '${protocols[@]}' -- "$cur"))
fi
;;
proxyjump)
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
;;
proxycommand | remotecommand | localcommand)
COMPREPLY=($(compgen -c -- "$cur"))
;;
pubkeyacceptedkeytypes)
COMPREPLY=($(compgen -W '$(_ssh_query "$2" key)' -- "$cur"))
;;
requesttty)
COMPREPLY=($(compgen -W 'no yes force auto' -- "$cur"))
;;
stricthostkeychecking)
COMPREPLY=($(compgen -W 'accept-new ask no off' -- "$cur"))
;;
syslogfacility)
COMPREPLY=($(compgen -W 'DAEMON USER AUTH LOCAL{0..7}' -- "$cur"))
;;
tunnel)
COMPREPLY=($(compgen -W 'yes no point-to-point ethernet' \
-- "$cur"))
;;
updatehostkeys | verifyhostkeydns)
COMPREPLY=($(compgen -W 'yes no ask' -- "$cur"))
;;
esac
return 0
}
# Try to complete -o SubOptions=
#
# Returns 0 if the completion was handled or non-zero otherwise.
_ssh_suboption_check()
{
# Get prev and cur words without splitting on =
local cureq=$(_get_cword :=) preveq=$(_get_pword :=)
if [[ $cureq == *=* && $preveq == -*o ]]; then
_ssh_suboption $cureq "$1"
return $?
fi
return 1
}
# Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument
_ssh_configfile()
{
set -- "${words[@]}"
while (($# > 0)); do
if [[ $1 == -F* ]]; then
if ((${#1} > 2)); then
configfile="$(dequote "${1:2}")"
else
shift
[[ ${1-} ]] && configfile="$(dequote "$1")"
fi
break
fi
shift
done
}
# With $1 set, look for public key files, else private
# shellcheck disable=SC2120
_ssh_identityfile()
{
[[ -z $cur && -d ~/.ssh ]] && cur=~/.ssh/id
_filedir
if ((${#COMPREPLY[@]} > 0)); then
COMPREPLY=($(compgen -W '${COMPREPLY[@]}' \
-X "${1:+!}*.pub" -- "$cur"))
fi
}
_ssh()
{
local cur prev words cword
_init_completion -n : || return
local configfile
_ssh_configfile
_ssh_suboption_check "$1" && return
local ipvx
case $prev in
-*b)
_ip_addresses
return
;;
-*c)
_ssh_ciphers "$1"
return
;;
-*[DeLpRW])
return
;;
-*[EFS])
_filedir
return
;;
-*i)
_ssh_identityfile
return
;;
-*I)
_filedir so
return
;;
-*J)
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
return
;;
-*l)
COMPREPLY=($(compgen -u -- "$cur"))
return
;;
-*m)
_ssh_macs "$1"
return
;;
-*O)
COMPREPLY=($(compgen -W 'check forward cancel exit stop' -- "$cur"))
return
;;
-*o)
_ssh_options "$1"
return
;;
-*Q)
_ssh_queries "$1"
return
;;
-*w)
_available_interfaces
return
;;
-*4*)
ipvx=-4
;;
-*6*)
ipvx=-6
;;
esac
if [[ $cur == -F* ]]; then
cur=${cur#-F}
_filedir
# Prefix completions with '-F'
COMPREPLY=("${COMPREPLY[@]/#/-F}")
cur=-F$cur # Restore cur
elif [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
else
_known_hosts_real ${ipvx-} -a ${configfile:+-F "$configfile"} -- "$cur"
local args
_count_args
if ((args > 1)); then
compopt -o filenames
COMPREPLY+=($(compgen -c -- "$cur"))
fi
fi
} &&
shopt -u hostcomplete && complete -F _ssh ssh slogin autossh sidedoor
# sftp(1) completion
#
_sftp()
{
local cur prev words cword
_init_completion || return
local configfile
_ssh_configfile
_ssh_suboption_check && return
local ipvx
case $prev in
-*[BDlPRs])
return
;;
-*[bF])
_filedir
return
;;
-*i)
_ssh_identityfile
return
;;
-*c)
_ssh_ciphers
return
;;
-*J)
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
return
;;
-*o)
_ssh_options
return
;;
-*S)
compopt -o filenames
COMPREPLY=($(compgen -c -- "$cur"))
return
;;
-*4*)
ipvx=-4
;;
-*6*)
ipvx=-6
;;
esac
if [[ $cur == -F* ]]; then
cur=${cur#-F}
_filedir
# Prefix completions with '-F'
COMPREPLY=("${COMPREPLY[@]/#/-F}")
cur=-F$cur # Restore cur
elif [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
else
_known_hosts_real ${ipvx-} -a ${configfile:+-F "$configfile"} -- "$cur"
fi
} &&
shopt -u hostcomplete && complete -F _sftp sftp
# things we want to backslash escape in scp paths
# shellcheck disable=SC2089
_scp_path_esc='[][(){}<>"'"'"',:;^&!$=?`\\|[:space:]]'
# Complete remote files with ssh. If the first arg is -d, complete on dirs
# only. Returns paths escaped with three backslashes.
# shellcheck disable=SC2120
_scp_remote_files()
{
local IFS=$'\n'
# remove backslash escape from the first colon
cur=${cur/\\:/:}
local userhost=${cur%%?(\\):*}
local path=${cur#*:}
# unescape (3 backslashes to 1 for chars we escaped)
# shellcheck disable=SC2090
path=$(command sed -e 's/\\\\\\\('$_scp_path_esc'\)/\\\1/g' <<<"$path")
# default to home dir of specified user on remote host
if [[ -z $path ]]; then
path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
fi
local files
if [[ $1 == -d ]]; then
# escape problematic characters; remove non-dirs
# shellcheck disable=SC2090
files=$(ssh -o 'Batchmode yes' $userhost \
command ls -aF1dL "$path*" 2>/dev/null |
command sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e '/[^\/]$/d')
else
# escape problematic characters; remove executables, aliases, pipes
# and sockets; add space at end of file names
# shellcheck disable=SC2090
files=$(ssh -o 'Batchmode yes' $userhost \
command ls -aF1dL "$path*" 2>/dev/null |
command sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e 's/[*@|=]$//g' \
-e 's/[^\/]$/& /g')
fi
COMPREPLY+=($files)
}
# This approach is used instead of _filedir to get a space appended
# after local file/dir completions, and -o nospace retained for others.
# If first arg is -d, complete on directory names only. The next arg is
# an optional prefix to add to returned completions.
_scp_local_files()
{
local IFS=$'\n'
local dirsonly=false
if [[ ${1-} == -d ]]; then
dirsonly=true
shift
fi
if $dirsonly; then
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
command sed -e "s/$_scp_path_esc/\\\\&/g" -e '/[^\/]$/d' -e "s/^/${1-}/"))
else
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
command sed -e "s/$_scp_path_esc/\\\\&/g" -e 's/[*@|=]$//g' \
-e 's/[^\/]$/& /g' -e "s/^/${1-}/"))
fi
}
# scp(1) completion
#
_scp()
{
local cur prev words cword
_init_completion -n : || return
local configfile
_ssh_configfile
_ssh_suboption_check && {
COMPREPLY=("${COMPREPLY[@]/%/ }")
return
}
local ipvx
case $prev in
-*c)
_ssh_ciphers
COMPREPLY=("${COMPREPLY[@]/%/ }")
return
;;
-*F)
_filedir
compopt +o nospace
return
;;
-*i)
_ssh_identityfile
compopt +o nospace
return
;;
-*J)
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
return
;;
-*[lP])
return
;;
-*o)
_ssh_options
return
;;
-*S)
compopt +o nospace -o filenames
COMPREPLY=($(compgen -c -- "$cur"))
return
;;
-*4*)
ipvx=-4
;;
-*6*)
ipvx=-6
;;
esac
_expand || return
case $cur in
!(*:*)/* | [.~]*) ;; # looks like a path
*:*)
_scp_remote_files
return
;;
esac
local prefix
if [[ $cur == -F* ]]; then
cur=${cur#-F}
prefix=-F
else
case $cur in
-*)
COMPREPLY=($(compgen -W '$(_parse_usage "${words[0]}")' \
-- "$cur"))
COMPREPLY=("${COMPREPLY[@]/%/ }")
return
;;
*/* | [.~]*)
# not a known host, pass through
;;
*)
_known_hosts_real ${ipvx-} -c -a \
${configfile:+-F "$configfile"} -- "$cur"
;;
esac
fi
_scp_local_files "${prefix-}"
} &&
complete -F _scp -o nospace scp
# ex: filetype=sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment