Description
In completions/apt-get, the _apt_get() function contains two separate
completion code paths:
- A "special subcommand" branch, entered via
if [[ -v special ]]; then ... fi,
which fires whenever a subcommand such as install, remove, purge,
autoremove, source, build-dep, download, or changelog is found
anywhere earlier on the command line.
- A generic long-option branch further down:
if [[ $cur == -* ]]; then
COMPREPLY=($(compgen -W '--no-install-recommends --install-suggests
--download-only --fix-broken ... ' -- "$cur"))
fi
The problem is that the install) arm inside the "special" case block ends
with ;;& (fall-through-and-retest), so execution always continues into the
final catch-all arm:
*)
COMPREPLY+=($(_xfunc apt-cache _apt_cache_packages))
;;
...which attempts package name completion, and the whole if [[ -v special ]]
block ends with an unconditional return.
As a result, whenever a subcommand like install is present anywhere on the
command line, the function returns before ever reaching the generic
[[ $cur == -* ]] branch further down — so long options can never be
completed after a subcommand, even though the option list clearly exists
in the script and is intended to work.
Steps to reproduce
apt-get install --no<TAB><TAB>
Expected: completion offers --no-install-recommends, --no-download,
--no-upgrade, --no-show-upgraded, etc. (all present in the hardcoded
compgen -W list later in the function).
Actual: nothing is completed. The shell instead silently attempts
_apt_cache_packages (package-name completion) against --no, which
naturally matches no package, so COMPREPLY stays empty.
This affects any apt-get subcommand handled by the special case
(install, remove, purge, autoremove, source, build-dep,
download, changelog) — i.e. exactly the subcommands people most commonly
want to pass options like --no-install-recommends, --purge,
--dry-run, etc. to.
Environment
bash-completion version: 1:2.11-8 (also reproducible by inspection on
upstream tags 2.9, 2.10, and 2.11)
apt/apt-get version: 2.8.3
- OS: Linux Mint 22.3 (Cinnamon), based on Ubuntu 24.04 "noble"
- GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
Description
In
completions/apt-get, the_apt_get()function contains two separatecompletion code paths:
if [[ -v special ]]; then ... fi,which fires whenever a subcommand such as
install,remove,purge,autoremove,source,build-dep,download, orchangelogis foundanywhere earlier on the command line.
The problem is that the
install)arm inside the "special"caseblock endswith
;;&(fall-through-and-retest), so execution always continues into thefinal catch-all arm:
...which attempts package name completion, and the whole
if [[ -v special ]]block ends with an unconditional
return.As a result, whenever a subcommand like
installis present anywhere on thecommand line, the function returns before ever reaching the generic
[[ $cur == -* ]]branch further down — so long options can never becompleted after a subcommand, even though the option list clearly exists
in the script and is intended to work.
Steps to reproduce
Expected: completion offers
--no-install-recommends,--no-download,--no-upgrade,--no-show-upgraded, etc. (all present in the hardcodedcompgen -Wlist later in the function).Actual: nothing is completed. The shell instead silently attempts
_apt_cache_packages(package-name completion) against--no, whichnaturally matches no package, so
COMPREPLYstays empty.This affects any
apt-getsubcommand handled by thespecialcase(
install,remove,purge,autoremove,source,build-dep,download,changelog) — i.e. exactly the subcommands people most commonlywant to pass options like
--no-install-recommends,--purge,--dry-run, etc. to.Environment
bash-completionversion:1:2.11-8(also reproducible by inspection onupstream tags
2.9,2.10, and2.11)apt/apt-getversion:2.8.3