From a2e26592218e1bebb55f18ab3e3b58f2fe7ec151 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 28 Jun 2026 06:55:32 +0900 Subject: [PATCH 1/4] fix(_comp_compgen_services): fix no completions without sysvdir This is a fix for a regression I introduced in commit da26178b (2023-08-13) with a *too* early return. Even when `_comp_sysvdirs` returns no service directories, the `services` array had gotten additional completions from the results of `systemctl`. The conditional for the result of `_comp_sysvdirs` should only apply to the completion generation based on the `sysvdirs` array. --- bash_completion | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bash_completion b/bash_completion index d7d06f2aff1..7fef7f596e5 100644 --- a/bash_completion +++ b/bash_completion @@ -2213,11 +2213,12 @@ _comp_compgen_xinetd_services() # @since 2.12 _comp_compgen_services() { - local sysvdirs - _comp_sysvdirs || return 1 - local status=1 - _comp_compgen -U sysvdirs -C "${sysvdirs[0]}" -- -f -X "@($_comp_backup_glob|functions|README)" && + + local sysvdirs + _comp_sysvdirs && + _comp_compgen -U sysvdirs -C "${sysvdirs[0]}" -- \ + -fX "@($_comp_backup_glob|functions|README)" && status=0 local _generated=$({ From c4c8c4b54040d4acc2688ed8fc040330d964fe12 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 28 Jun 2026 07:14:28 +0900 Subject: [PATCH 2/4] feat(_comp_compgen_sysv_services): factorize SysV service generation "_comp_compgen_services" (bash_completion) and "{invoke,update}-rc.d" have similar logics to generate the service names based on the directory structures for SysV init services. This patch provides a single function "_comp_compgen_sysv_services" for the common logic. There have been some differences in the excluded filenames between "_comp_compgen_services" and "{invoke,update}-rc.d": * The function "_comp_compgen_services" exclude the file "functions", which contains utilities that are used by other service scripts. The completions for "{invoke,update}-rc.d" exclude "*.sh" and also the files starting with "README*". In the new generator "_comp_compgen_sysv_services", we exclude all "*.sh", "functions", and "README*". * Another difference is the extraction of the SysV directory. The completions for "{invoke,update}-rc.d" only checked /etc/rc.d/init.d and /etc/init.d, but "_comp_compgen_services" based on "_comp_sysvdirs" checked also /etc/slackware-version when neither /etc/rc.d/init.d nor /etc/init.d is found. In the new generator, we use "_comp_sysvdirs" to identify a SysV service directory. --- bash_completion | 18 ++++++++++++------ completions-core/invoke-rc.d.bash | 18 ++++++++++-------- completions-core/update-rc.d.bash | 9 ++------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/bash_completion b/bash_completion index 7fef7f596e5..ce5a0609f76 100644 --- a/bash_completion +++ b/bash_completion @@ -2207,6 +2207,17 @@ _comp_compgen_xinetd_services() fi } +# This function completes on SysV init services +# +# @since 2.18 +_comp_compgen_sysv_services() +{ + local sysvdirs + _comp_sysvdirs && + _comp_compgen -U sysvdirs -C "${sysvdirs[0]}" -- \ + -fX "@($_comp_backup_glob|functions|*.sh|README*)" +} + # This function completes on services # # @return 0 if at least one completion is generated, or 1 otherwise. @@ -2214,12 +2225,7 @@ _comp_compgen_xinetd_services() _comp_compgen_services() { local status=1 - - local sysvdirs - _comp_sysvdirs && - _comp_compgen -U sysvdirs -C "${sysvdirs[0]}" -- \ - -fX "@($_comp_backup_glob|functions|README)" && - status=0 + _comp_compgen_sysv_services && status=0 local _generated=$({ systemctl list-units --full --all || diff --git a/completions-core/invoke-rc.d.bash b/completions-core/invoke-rc.d.bash index 323da9477d9..24280b6af77 100644 --- a/completions-core/invoke-rc.d.bash +++ b/completions-core/invoke-rc.d.bash @@ -7,11 +7,7 @@ _comp_cmd_invoke_rc_d() local cur prev words cword comp_args _comp_initialize -- "$@" || return - local sysvdir options - - [[ -d /etc/rc.d/init.d ]] && sysvdir=/etc/rc.d/init.d || - sysvdir=/etc/init.d - + local options options=(--help --quiet --force --try-anyway --disclose-deny --query --no-fallback) @@ -21,9 +17,15 @@ _comp_cmd_invoke_rc_d() local exclude="@(${words[*]})" _comp_unlocal IFS _comp_compgen -- -W '"${options[@]}"' -X "$exclude" - # shellcheck disable=SC2154 - _comp_compgen -aC "$sysvdir" -- -f -X "@(README*|*.sh|$_comp_backup_glob)" - elif [[ -x $sysvdir/$prev ]]; then + _comp_compgen -a sysv_services + return + fi + + local sysvdir + [[ -d /etc/rc.d/init.d ]] && sysvdir=/etc/rc.d/init.d || + sysvdir=/etc/init.d + + if [[ -x $sysvdir/$prev ]]; then _comp_compgen_split -- "$(command sed -e 'y/|/ /' \ -ne 's/^.*Usage:[ ]*[^ ]*[ ]*{*\([^}"]*\).*$/\1/p' \ "$sysvdir/$prev")" diff --git a/completions-core/update-rc.d.bash b/completions-core/update-rc.d.bash index c794290b674..e0292228a4c 100644 --- a/completions-core/update-rc.d.bash +++ b/completions-core/update-rc.d.bash @@ -7,13 +7,8 @@ _comp_cmd_update_rc_d() local cur prev words cword comp_args _comp_initialize -- "$@" || return - local sysvdir services options - - [[ -d /etc/rc.d/init.d ]] && sysvdir=/etc/rc.d/init.d || - sysvdir=/etc/init.d - - # shellcheck disable=SC2154 - _comp_compgen -v services -C "$sysvdir" -- -f -X "@(README*|*.sh|$_comp_backup_glob)" + local services options + _comp_compgen -v services sysv_services options=(-f -n) if [[ $cword -eq 1 || $prev == -* ]]; then From fa45b5aac8fc9458fda4f96a5484895dd7283765 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 28 Jun 2026 07:15:11 +0900 Subject: [PATCH 3/4] refactor(invoke-rc.d): use "_comp_sysvdirs" We can also use "_comp_sysvdirs" in identifying the service script for the completion of an action name. --- completions-core/invoke-rc.d.bash | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/completions-core/invoke-rc.d.bash b/completions-core/invoke-rc.d.bash index 24280b6af77..b15d7ec3049 100644 --- a/completions-core/invoke-rc.d.bash +++ b/completions-core/invoke-rc.d.bash @@ -21,14 +21,11 @@ _comp_cmd_invoke_rc_d() return fi - local sysvdir - [[ -d /etc/rc.d/init.d ]] && sysvdir=/etc/rc.d/init.d || - sysvdir=/etc/init.d - - if [[ -x $sysvdir/$prev ]]; then + local sysvdirs + if _comp_sysvdirs && [[ -x ${sysvdirs[0]}/$prev ]]; then _comp_compgen_split -- "$(command sed -e 'y/|/ /' \ -ne 's/^.*Usage:[ ]*[^ ]*[ ]*{*\([^}"]*\).*$/\1/p' \ - "$sysvdir/$prev")" + "${sysvdirs[0]}/$prev")" else COMPREPLY=() fi From 5557fbe488c10cbc07a604cc330e86ee1de17efb Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 28 Jun 2026 06:44:42 +0900 Subject: [PATCH 4/4] fix(_comp_compgen_sysv_services): do not generate names in subdirs This is a regression by Ref. [1]. In Ref. [1], I have replaced the combination of "_comp_expand_glob" and "_comp_compgen -- -W" with "_comp_compgen -C -- -f". However, I realized that this strategy would cause generation of the filenames in subdirectories when $cur contains "/" [2]. To avoid this, one can exclude candidates containing a slash by -X '*/*'. [1] https://github.com/scop/bash-completion/pull/1553 [2] https://github.com/scop/bash-completion/pull/1639#discussion_r3455787941 --- bash_completion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash_completion b/bash_completion index ce5a0609f76..70f33282c1d 100644 --- a/bash_completion +++ b/bash_completion @@ -2215,7 +2215,7 @@ _comp_compgen_sysv_services() local sysvdirs _comp_sysvdirs && _comp_compgen -U sysvdirs -C "${sysvdirs[0]}" -- \ - -fX "@($_comp_backup_glob|functions|*.sh|README*)" + -fX "@($_comp_backup_glob|functions|*.sh|README*|*/*)" } # This function completes on services