bash-completion
bash-completion copied to clipboard
bash command completion has a problem with sudo command
Describe the bug
When the command completion function starts running
there are three variables automatically setting $1
, $2
, $3
.
and $2
is not always the same as ${COMP_WORDS[COMP_CWORD]}
.
-
if
$2
value is a member of$COMP_WORDBREAKS
variable then it's value is empty by defaultex) command --foo=[tab]
$2
: (empty)${COMP_WORDS[COMP_CWORD]}
:=
-
if
$2
value start with"
or'
(single or double quote) then it's quote removed ("foo
-->foo
)ex) command --foo "bar[tab]
$2
:bar
${COMP_WORDS[COMP_CWORD]}
:"bar
this is an intended work for making completion function simpler
but if i use sudo in front of a command then
$2
value is always the same as ${COMP_WORDS[COMP_CWORD]}
This is a different behavior to the bash default and problematic.
and ends up can not use $2
variable and force to use
${COMP_WORDS[COMP_CWORD]}
to support sudo
Versions
- [ ] Operating system name/distribution and version:
Operating System: Ubuntu 22.04.1 LTS
Kernel: Linux 5.15.0-43-generic Architecture: x86-64 - [ ] bash version: 5.1.16(1)-release
- [ ] bash-completion version: 2.11
The call of the completion functions for the commands after another command (such as sudo
) is emulated by _command_offset
. In particular, the arguments passed to the completion function is determined here.
- if
$2
value is a member of$COMP_WORDBREAKS
variable then it's value is empty by default ex) command --foo=[tab]$2
: (empty)${COMP_WORDS[COMP_CWORD]}
:=
- if
$2
value start with"
or'
(single or double quote) then it's quote removed ("foo
-->foo
) ex) command --foo "bar[tab]$2
:bar
${COMP_WORDS[COMP_CWORD]}
:"bar
Is this the exact rule? If the exact rule is known, I think we can implement it in _command_offset
, but Bash Reference Manual doesn't seem to clarify the details.
Bash Reference Manual - §8.6 Programmable Completion
[...] When the function or command is invoked, 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. [...]
I have tried it a little with the plain Bash (5.1.16/Fedora 36), but the rule seems to be a bit more complicated. For special characters in COMP_WORDBREAKS
(particularly =
and :
),
$ _test1() { printf '\e7\n\e[J'; declare -p COMP_WORDS COMP_CWORD; (($#)) && printf '<%s>' "$@"; printf '\e8'; } && complete -F _test1 test1
$ cat -A <<< "$COMP_WORDBREAKS"
^I$
"'@><=;|&(:$
$ test1 --foo==[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo" [2]="==")
declare -- COMP_CWORD="2"
<test1><><--foo>
$ test1 --foo=:[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo" [2]="=:")
declare -- COMP_CWORD="2"
<test1><><--foo>
$ test1 --foo'=[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo'=")
declare -- COMP_CWORD="1"
<test1><=><test1>
$ test1 --foo =[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo" [2]="=")
declare -- COMP_CWORD="2"
<test1><><--foo>
$ test1 --foo '=[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo" [2]="'=")
declare -- COMP_CWORD="2"
<test1><=><--foo>
$ test1 --foo '='[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="--foo" [2]="'='")
declare -- COMP_CWORD="2"
<test1><'='><--foo>
For double quotation,
$ test1 a"b[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="a\"b")
declare -- COMP_CWORD="1"
<test1><b><test1>
$ test1 a"b"[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="a\"b\"")
declare -- COMP_CWORD="1"
<test1><a"b"><test1>
$ test1 a"b"c[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="a\"b\"c")
declare -- COMP_CWORD="1"
<test1><a"b"c><test1>
$ test1 a"b"c"[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="a\"b\"c\"")
declare -- COMP_CWORD="1"
<test1><><test1>
Also, $2
changes depending on the position of the cursor (where the cursor position is indicated by [TAB]
):
$ test1 a[TAB]bcd
declare -a COMP_WORDS=([0]="test1" [1]="abcd")
declare -- COMP_CWORD="1"
<test1><a><test1>
$ test1 ab[TAB]cd
declare -a COMP_WORDS=([0]="test1" [1]="abcd")
declare -- COMP_CWORD="1"
<test1><ab><test1>
$ test1 abc[TAB]d
declare -a COMP_WORDS=([0]="test1" [1]="abcd")
declare -- COMP_CWORD="1"
<test1><abc><test1>
]$ test1 abcd[TAB]
declare -a COMP_WORDS=([0]="test1" [1]="abcd")
declare -- COMP_CWORD="1"
<test1><abcd><test1>
@mug896 Could you investigate and summarize the exact rule?
I asked this problem to the current bash maintainer. and he said without bash-completion installed get the same null second argument with or without specifying 'sudo'
I think no needs to parse quotes directly
In _sudo
function just backup the $2
, $3
variables
and pass the values to the _hello
function something like this
bash$ sudo hello aa bb cc
complete -F _sudo sudo
complete -F _hello hello
_sudo() {
local two_bak=$2 three_bak=$3 # backup $2, $3
. . .
_sudo_sub
}
_sudo_sub() {
. . .
_hello "hello" "$two_bak" "$three_bak"
}
I think that would only work if we would just care about sudo
, but we also need to care about completions for other commands that calls _command_offset
. Also, to save the original arguments passed to the completion functions, we need to change the basic use pattern of bash-completion utility functions, which starts from the declaration of a pre-defined set of local variables and _init_completion
. Furthermore, _command_offset
and other utilities of bash-completion are called by external completions, i.e., custom completion functions written by users or third-party completion functions written by authors of applications, which makes it difficult to introduce breaking changes to the existing utility functions.
For these reasons, to follow your suggestion, we need to pay large efforts. We need to 1) design a new basic interface of bash-completion utilities for completion functions with new names or options, 2) rewrite all the existing completion functions to follow the new interface (there are currently 567 such functions in the repository), and 3) deprecate related existing functions or usages like _init_completion || return
. We also need to 4) announce the interface changes to the authors of external completions and 5) submit pull requests if necessary. The question is whether it is worth making such large efforts to solve this issue. In particular, basically, we cannot change the basic interface used by external completions unless there is a sufficient reason. Even if we decided to break the existing interface, this would be a several-year project (including design discussion, implementations, tests, and reviews), and some continuous contributors need to voluntarily work on them, but at least I'm not willing to work on them.
check this script out.
i made this for fixing the bug of sudo completion function.
and it works for me
though i'm not using bash-completion package in my completion function.
i think you should fix this bug anyway.
because of this bug every completion function has to start with
local cmd=$1 cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]};
[[ ${COMP_LINE:COMP_POINT-1:1} = " " ]] && cur=""
and adds [[ $cur == "=" ]] && cur=""
or
[[ $cur == @(\"*|\'*) ]] && cur=${cur:1}
lines
instead of just writing local cmd=$1 cur=$2 prev=$3
to support bash-completion package
_sudo()
{
local arr func cmd=${COMP_WORDS[1]} cur=$2 i
if (( COMP_CWORD == 1 )); then
COMPREPLY=($( compgen -A command -- "$cur" ))
return
fi
if ! complete -p "$cmd" &> /dev/null; then
_completion_loader "$cmd" &> /dev/null
fi
if arr=( $(complete -p "$cmd" 2> /dev/null) ); then
for (( i = 1; i < ${#arr[@]}; i++ )); do
[[ ${arr[i]} == -F ]] && { func=${arr[i + 1]}; break ;}
done
if [[ -n $func ]]; then
COMP_LINE=${COMP_LINE##$1+( )}
let COMP_POINT-="COMP_POINT - ${#COMP_LINE}"
unset -v 'COMP_WORDS[0]'
COMP_WORDS=( "${COMP_WORDS[@]}" )
let COMP_CWORD--
"$func" "$cmd" "$2" "$3"
fi
fi
}
complete -o default -o bashdefault -F _sudo sudo
Thanks, but I know how to fix the issue if it is fine to fix only sudo
as you are suggesting.
As I have explained in https://github.com/scop/bash-completion/issues/790#issuecomment-1224159227, the point is that we wouldn't like to fix the issue for each command like sudo
, ionice
, ccache
, find
, gdb
, screen
, strace
, sudo
, timeout
, valgrind
, watch
, xvfb-run
... one by one separately. We should rather fix the utility function _command_offset
because the implementation of _command_offset
causes the present problem. The problem is that we cannot easily change the interface of _command_offset
, so
- One option is to implement the special rule to determine
$2
from${COMP_WORDS{COMP_CWORD]}
in_command_offset
. This is what I initially suggested. This solves the issue without requiring any changes to the completion functions inbash-completion
and in external completions. - Another option is to save the original
$2
passed by the readline to a fixed position and let_command_offset
pick up from that position. However, this requires a change of the standard patternlocal cur prev words cword split; _init_completion -s || return
. - Another option is to add a new implementation of
_command_offset2
or add a new option to_command_offset
to specify a preferred$2
as an argument. However, this also involves the interface change so we need to rewrite all the calls of_command_offset
. Of course, we can rewrite all such instances in thebash-completion
project, but it is not the case for external completions.
The problem is that the bash-completion package installed by default all linux distros.
so even users not using the package have to use the sudo completion function in the package.
The only command to concern is sudo
command, not any other commands.
and the sudo completion function in the package change $2
default value
to ${COMP_WORDS[COMP_CWORD]}
.
I had some tests with the sudo function in the package and my sudo function above
with ccache, find, gcc, strace, timeout, valgrind, watch ... commands.
and they all work the same without problems
because that commands use _init_completion || return
. and not use $2
variable directly
The problem is that the bash-completion package installed by default all linux distros. so even users not using the package have to use the sudo completion function in the package.
I am not trying to say that the current bash-completion doesn't need to be fixed. You don't have to repeat in every your reply that the current behavior is a problem and it needs to be fixed. We are talking about the solution. As I have mentioned in my previous replies, the solution that you are suggesting has another maintenance problem though I know that it solves the original problem of sudo
. You are repeating that your suggestion solves the original problem, but you don't seem to provide a solution to the maintenance problem. Unless you provide a satisfactory answer to the maintenance problem or consider other solutions, I think the discussion doesn't proceed.
The only command to concern is
sudo
command, not any other commands.
Why?
and the sudo completion function in the package change
$2
default value to${COMP_WORDS[COMP_CWORD]}
.
These other commands are also affected by the current behavior of bash-completion because of the same problem in _command_offset
. I won't create the test cases of every command for you, but that can be easily reproduced by, for example,
$ _test1() { printf '\e7\n\e[J'; printf '<%s>' "$@"; printf '\e8'; } && complete -F _test1 test1
$ test1 --foo=
<test1><><--foo>
$ sudo test1 --foo=
<test1><=><--foo>
$ ccache test1 --foo=
<test1><=><--foo>
$ find . -exec test1 --foo=
<test1><=><--foo>
$ gdb --args test1 --foo=
<test1><=><--foo>
$ strace test1 --foo=
<test1><=><--foo>
I had some tests with the sudo function in the package and my sudo function above with ccache, find, gcc, strace, timeout, valgrind, watch ... commands. and they all work the same without problems because that commands use
_init_completion || return
. and not use$2
variable directly
Could you describe in more detail how you implemented or patched the completion functions for those commands and how did you test them?
I never thought of completions in the command line options that way.
I'm sorry about my ignorance.
my preferred way is to adding the second argument of $2
value
to the _command_offset
function using the command like sed.
but there are external completions as you said.
It seems your first option is way to go
but that needs to parse the ${COMP_WORDS{COMP_CWORD]}
value twice
in the script (including quotes, escape sequence). I think it's terrible.
how about using shopt -e extdebug
option ?
if you enable extdebug option then you can obtain ancestor function's
argument count and values like this
#!/bin/bash
_command_offset() {
echo "${FUNCNAME[0]} function argc: ${BASH_ARGC[0]}"
echo "${FUNCNAME[0]} function arg1: ${BASH_ARGV[1]}"
echo "${FUNCNAME[0]} function arg2: ${BASH_ARGV[0]}"
echo "${FUNCNAME[1]} function argc: ${BASH_ARGC[1]}"
echo "${FUNCNAME[1]} function arg1: ${BASH_ARGV[4]}"
echo "${FUNCNAME[1]} function arg2: ${BASH_ARGV[3]}"
echo "${FUNCNAME[1]} function arg3: ${BASH_ARGV[2]}"
}
_foo() {
_command_offset 44 55
}
main() {
_foo 11 22 33
}
shopt -s extdebug
main
#####################################
bash$ ./test.sh
_command_offset function argc: 2
_command_offset function arg1: 44
_command_offset function arg2: 55
_foo function argc: 3
_foo function arg1: 11
_foo function arg2: 22
_foo function arg3: 33
my preferred way is to adding the second argument of
$2
value > to the_command_offset
function using the command like sed. but there are external completions as you said.
I'm actually currently thinking of the possibility of the hybrid solution of analyzing ${COMP_WORDS{COMP_CWORD]}
and passing the original $2
: We can add a new option to _command_offset
to pass the original $2
(like _command_offset --cur="$2" $offset
). When the original $2
is passed, _command_offset
can just use the passed value. When the option is not specified, _command_offset
analyzes ${COMP_WORDS{COMP_CWORD]}
to determine a value. For the completion functions inside the bash-completion project, we can modify the codes to pass the original $2
. It is better to modify also external completions so that the original $2
is passed to _command_offset
, but they would still work mostly even if they are not modified because $2
is reconstructed from ${COMP_WORDS{COMP_CWORD]}
.
It seems your first option is way to go but that needs to parse the
${COMP_WORDS{COMP_CWORD]}
value twice in the script (including quotes, escape sequence). I think it's terrible.
I'm currently not sure how hard that is. Does it really require us an authentic shell parser? That is the reason we need to investigate the exact rule used by Bash in order to estimate whether this solution can be useful. If that can be processed by regular expressions like this in most cases, that is fine. It is possibly impossible to perfectly reproduce the original rule, but even in that case, I guess the most realistic cases can be covered by some regular expressions.
how about using
shopt -e extdebug
option ?
Actually, I also thought about that direction independently, but this direction also seems to have other problems that are hard to solve.
- First,
extdebug
doesn't just enableBASH_ARGV
andBASH_ARGC
, but also changes the semantics ofDEBUG
/ERR
/RETURN
traps. Specifically, we can set these traps for each function separately whenextdebug
is ~~not~~ turned off, but it becomes impossible whenextdebug
is turned on. This means that if we setextdebug
globally, it can break existing configurations that use these traps. In particular,DEBUG
trap is used by various Bash configurations like bash-preexec, iTerm2 shell integration, wezterm shell integration, starship, liqiuidprompt, etc. - Another concern is the performance. With
extdebug
, the above traps start to be inherited by all the function calls, so the shell can be significantly slower than withoutextdebug
. Even when no traps are set, I have doubts on the performance ofBASH_ARGV
andextdebug
. Once I have measured the performance of a utility function that uses the hack ofBASH_ARGV
withextdebug
introduced in Pure Bash Bible, but the result was by far inferior to the naive implementation. (By the way, the function of Pure Bash Bible is also broken by globally setextdebug
, though it can be easily fixed.)
Then, another possibility that comes to our mind is to locally set extdebug
instead of globally setting extdebug
. We might think of temporarily turning extdebug
on in _command_offset
, getting the arguments, and finally unsetting extdebug
(or restoring the original state of extdebug
). However, this naive solution doesn't work because BASH_ARGV
only contains the arguments after we set extdebug
. When _command_offset
is called, it is too late to set extdebug
in order to retrieve the arguments of the caller by BASH_ARGV
.
Next, we might consider locally setting extdebug
inside the top-level completion function prior to the call of _command_offset
. This can be technically possible if the top-level completion function calls _init_completion
at the beginning. We can set extdebug
when _init_completion
is called. At the same time, _init_completion
shall set the RETURN
trap for the top-level completion function. We can reset extdebug
in the RETURN
trap. This kind of strategy was experimentally implemented in . PR #739 but is not yet fully tested. This strategy also has some other problems:
- We cannot ensure that the
RETURN
trap is called, for example, when the user cancels the completion by C-c (SIGINT). In such a case, we fail to restore the global setting ofextdebug
. Issue #786 is essentially the same problem. We may think of trapping SIGINT, but we are not sure if that covers all the similar cases. - This doesn't always work for external completions. For this to work,
_init_completion
needs to be called from the top level of the completion function, but_init_completion
has never been put such a restriction, so external completions may call it from inside child functions. Also, there seem to be even some external completion functions that do not call_init_completion
but only call_command_offset
. We can find such completion functions, e.g., here and there.
As you already know, quotes are members of the $COMP_WORDBREAKS
variable
and have different behavior than other WORDBREAKERS.
The primary usage of quotes in tab completions is
to input multiple words sentence something like this
1) install
2) Linked Base for node-1 and node-2 # completion list
3) Linked Base for node-1 and node-3
4) hostname hosts setup
sh$ hello --foo "Linked Ba[tab]
sh$ hello --foo="Linked Ba[tab]
sh$ hello -A "Linked Ba[tab]
and if a user wants to include quotes in the completion list
then he first has to escape the quotes like (1) when assign COMPREPLY
variable
in case (2) will not appear the quotes in the completion list when user enter tab
how to tab complete the quotes in the prompt ? you also need to escape the quotes to complete.
install
Linked Base for \"node-1\" and \"node-2\" ---- (1)
Linked Base for "node-1" and "node-3" ---- (2)
hostname hosts setup
nobody uses quotes in tab completion like this.
test1 a"b[TAB]
test1 a"b"[TAB]
test1 a"b"c[TAB]
test1 a"b"c"[TAB]
# but this is possible
test1 "ab[TAB]
also nobody uses tab completion on already completed word like this.
so these two cases are no need to concern to set the bash's original $2
variable.
test1 a[TAB]bcd
test1 ab[TAB]cd
test1 abc[TAB]d
# but this case is need to concern because following usage pattern
test1 [TAB]abcd
sh$ hello -a foo -b bar # user wants to change option argument of -a
sh$ hello -a [TAB]-b bar # $2: empty ${COMP_WORDS[COMP_CWORD]}: -b
# because of the current bash-completion bug every completion function
# that does not use base-completion package has to add this line on top.
# if a user can use the bash's original $2 value then don't need this line
# [[ ${COMP_LINE:COMP_POINT-1:1} = " " ]] && cur=""
So my recommandation is that there is no need to parse
${COMP_WORDS[COMP_CWORD]}
variable to set $2
variable.
and this is enough to set the original $2
variable.
if [[ ${COMP_WORDS[COMP_CWORD]} == @(\"*|\'*) ]]; then
set -- "$1" "${COMP_WORDS[COMP_CWORD]:1}" "${COMP_WORDS[COMP_CWORD-1]}"
elif [[ $COMP_WORDBREAKS == *${COMP_WORDS[COMP_CWORD]}* ]] ||
[[ ${COMP_LINE:COMP_POINT-1:1} = " " ]]; then
set -- "$1" "" "${COMP_WORDS[COMP_CWORD-1]}"
else
set -- "$1" "${COMP_WORDS[COMP_CWORD]}" "${COMP_WORDS[COMP_CWORD-1]}"
fi
I currently noticed that bash-completion package also set bash's default
$3
value to empty then you have to use${COMP_WORDS[COMP_CWORD-1]}
for setting$3
variable
All these are the factors that make people stop trying to learn completion functions and only a few people make it. think about how confusing it ! if the bug I suggested is fixed, then a lot of confusion will be removed..
I created PR #791 that determines $2
based on ${COMP_WORDS[CWORD]}
.
I have also implemented what you have suggested, (i.e., letting each completion function pass the original $2
) in https://github.com/akinomyoga/bash-completion/commit/3d5869cb5d7eefbc4db673cc88fbe56d38a6878c, but it is not included in the PR currently because the extraction from ${COMP_WORDS[CWORD]}
seems to just work fine and the _command_offset
interface doesn't seem to need to be changed.
The primary usage of quotes in tab completions is to input multiple words sentence something like this [...]
I am talking about the pattern a"b"c"d"e
but not the case like a"b\"c\"d"e
. If you call "a\"b\"c"
primary usage, I am talking about secondary usage.
nobody uses quotes in tab completion like this. [...]
also nobody uses tab completion on already completed word like this. [...]
I'm wondering how many people that "nobody" is out of. How many people did you actually confirm with that they do not use them? As for the former, I do use like /path/to/"a directory containing space"/sub/directory/
. I can easily enumerate more examples:
$ gcc -L"/xxx/yyy/zzz" -L"/xxx/yyy/www" a.c -lfoo -lbar -Wl,-R"/xxx/yyy/zzz",-R"[TAB]
$ echo "result.a=$(xxx).b="*".c=1.txt" or result.a-"$(xxx)".b-*.c-"[TAB]
As for the latter, many people use it as far as their keyboard has the cursor key ⬅️. Consider the reason why Readline has an option skip-completed-text
. If nobody would really use it, the option skip-completed-text
doesn't have meaning. Anyway, both cases are valid Bash syntax and don't explicitly fail. In general, as far as a feature or usage is not explicitly forbidden by Bash, there is probably someone using it in the world, so we can hardly say nobody about any features.
Even if nobody is using them, I'm wondering if there is a reason to prefer an incomplete ad-hoc solution to the general solution.
I made this simple parser for parsing the ${COMP_WORDS[COMP_CWORD]}
value
to set up the original $2
variable based on your test cases.
please check this out whether need to fix or add functionality.
_parse_print()
{
echo
echo '$1: '"[$1]"
echo '$2: '"[$2]"
echo '$3: '"[$3]"
}
_parse()
{
local comp=${COMP_WORDS[COMP_CWORD]}
local match=0 two i
if [[ ${comp:0:1} != @(\"|\') && $COMP_WORDBREAKS == *"${comp:0:1}"* ]]; then
_parse_print "$1" "" "${COMP_WORDS[COMP_CWORD-1]}"
return
fi
for (( i = 0; i < ${#comp}; i++ )); do
[[ ${COMP_LINE:0:COMP_POINT} == *"${comp:0:i+1}" ]] && let match=i+1
done
local str=${comp:0:match}
local open=-1 curq=""
for ((i = 0; i < ${#str}; i++)); do
case ${str:i:1} in
\")
[[ $curq == single ]] && continue
(( open == -1 )) && { open=$i; curq="double" ;} || { open=-1; curq="" ;}
;;
\')
[[ $curq == double ]] && continue
(( open == -1 )) && { open=$i; curq="single" ;} || { open=-1; curq="" ;}
;;
\\)
[[ ${str:i+1:1} == @(\"|\'|\\) && $curq != single ]] && let i++
;;
esac
done
if (( open == -1 )); then
two=$str
else
str=${str:open}
two=${str#@(\"|\')}
fi
_parse_print "$1" "$two" "${COMP_WORDS[COMP_CWORD-1]}"
}
complete -F _parse parse
Thanks, but I actually have already implemented it in #791. My current implementation is just two regex matching and covers all the test cases that I have obtained by Bash 5.2-rc3. Note that I have finally investigated the Bash behavior by myself and added more test cases in addition to the ones in https://github.com/scop/bash-completion/issues/790#issuecomment-1223874518.
The actual rule seems to be more complicated than something that can be guessed from the initial test cases in https://github.com/scop/bash-completion/issues/790#issuecomment-1223874518. In fact, I have tested your implementation with my test cases including new ones, but it only passes 48/126 cases. (The implementation of #791 passes all the cases). Here are the failing cases of your implementation (edit: sorry, I forgot to include the information of COMP_WORDBREAKS for each test case. Now I have added it below):
# default COMP_WORDBREAKS
159: failed: input=<a`echo w> output=<a`echo w> expect=<w>
163: failed: input=<a`bbb ccc`> output=<a`bbb ccc`> expect=<ccc`>
170: failed: input=<$'a b'c`d e> output=<$'a b'c`d e> expect=<e>
171: failed: input=<a`b'c'd e> output=<a`b'c'd e> expect=<e>
172: failed: input=<a`b'c'd e f> output=<a`b'c'd e f> expect=<f>
173: failed: input=<a`$(echo world> output=<a`$(echo world> expect=<world>
175: failed: input=<a`$'b c\'d e$'f g\'> output=<a`$'b c\'d e$'f g\'> expect=<g\'>
176: failed: input=<a`$'b c\'d e$'f g\'h i> output=<a`$'b c\'d e$'f g\'h i> expect=<i>
177: failed: input=<a`$'b c\'d e$'f g\'h i`j> output=<a`$'b c\'d e$'f g\'h i`j> expect=<i`j>
178: failed: input=<a`$'b c\'d e'f g'> output=<a`$'b c\'d e'f g'> expect=<g'>
179: failed: input=<a`a;> output=<a`a;> expect=<>
180: failed: input=<a`x=> output=<a`x=> expect=<>
181: failed: input=<a`x=y> output=<a`x=y> expect=<y>
182: failed: input=<a`b|> output=<a`b|> expect=<>
183: failed: input=<a`b:c> output=<a`b:c> expect=<c>
184: failed: input=<a`b&> output=<a`b&> expect=<>
# COMP_WORDBREAKS=@$IFS
188: failed: input=<a`b@c> output=<a`b@c> expect=<@c>
# COMP_WORDBREAKS=z$IFS
193: failed: input=<a`bzc> output=<a`bzc> expect=<c>
194: failed: input=<a`bzcdze> output=<a`bzcdze> expect=<e>
195: failed: input=<a`bzcdzze> output=<a`bzcdzze> expect=<e>
196: failed: input=<a`bzcdzzze> output=<a`bzcdzzze> expect=<e>
# COMP_WORDBREAKS='$'$IFS
202: failed: input=<a`b$> output=<a`b$> expect=<$>
203: failed: input=<a`b$x> output=<a`b$x> expect=<$x>
204: failed: input=<a`b${> output=<a`b${> expect=<${>
205: failed: input=<a`b${x}> output=<a`b${x}> expect=<${x}>
206: failed: input=<a`b${x}y> output=<a`b${x}y> expect=<${x}y>
207: failed: input=<a`b$=> output=<a`b$=> expect=<$=>
208: failed: input=<a`b$.> output=<a`b$.> expect=<$.>
210: failed: input=<a`b$"a"> output=<a`b$"a"> expect=<$"a">
# COMP_WORDBREAKS='\'$IFS
216: failed: input=<a`b\cd> output=<a`b\cd> expect=<cd>
217: failed: input=<a`b\cde\fg> output=<a`b\cde\fg> expect=<fg>
218: failed: input=<a`b\c\\a> output=<a`b\c\\a> expect=<\a>
219: failed: input=<a`b\c\\\a> output=<a`b\c\\\a> expect=<a>
220: failed: input=<a`b\c\\\\a> output=<a`b\c\\\\a> expect=<\a>
221: failed: input=<a`b\c\a\a> output=<a`b\c\a\a> expect=<a>
222: failed: input=<a`b\> output=<a`b\> expect=<>
223: failed: input=<a`b\\> output=<a`b\\> expect=<\>
224: failed: input=<a`b\\\> output=<a`b\\\> expect=<>
# COMP_WORDBREAKS='\$'$IFS
228: failed: input=<a`b$\> output=<a`b$\> expect=<>
229: failed: input=<a`b\$> output=<a`b\$> expect=<$>
# COMP_WORDBREAKS='$z@'$IFS
233: failed: input=<a$z> output=<a$z> expect=<>
234: failed: input=<a$$z> output=<a$$z> expect=<>
235: failed: input=<a$$> output=<a$$> expect=<$>
236: failed: input=<a$@> output=<a$@> expect=<@>
237: failed: input=<a$$@> output=<a$$@> expect=<@>
# COMP_WORDBREAKS='!'$IFS
240: failed: input=<a`b!> output=<a`b!> expect=<>
241: failed: input=<a`b!c> output=<a`b!c> expect=<c>
# COMP_WORDBREAKS='#'$IFS
243: failed: input=<a`b#> output=<a`b#> expect=<>
244: failed: input=<a`b#c> output=<a`b#c> expect=<c>
# COMP_WORDBREAKS='%'$IFS
246: failed: input=<a`b%> output=<a`b%> expect=<>
247: failed: input=<a`b%c> output=<a`b%c> expect=<c>
# COMP_WORDBREAKS='*'$IFS
249: failed: input=<a`b*> output=<a`b*> expect=<>
250: failed: input=<a`b*c> output=<a`b*c> expect=<c>
# COMP_WORDBREAKS='+'$IFS
252: failed: input=<a`b+> output=<a`b+> expect=<>
253: failed: input=<a`b+c> output=<a`b+c> expect=<c>
# COMP_WORDBREAKS=','$IFS
255: failed: input=<a`b,> output=<a`b,> expect=<>
256: failed: input=<a`b,c> output=<a`b,c> expect=<c>
# COMP_WORDBREAKS='-'$IFS
258: failed: input=<a`b-> output=<a`b-> expect=<>
259: failed: input=<a`b-c> output=<a`b-c> expect=<c>
# COMP_WORDBREAKS='.'$IFS
261: failed: input=<a`b.> output=<a`b.> expect=<>
262: failed: input=<a`b.c> output=<a`b.c> expect=<c>
# COMP_WORDBREAKS='/'$IFS
264: failed: input=<a`b/> output=<a`b/> expect=<>
265: failed: input=<a`b/c> output=<a`b/c> expect=<c>
# COMP_WORDBREAKS='?'$IFS
267: failed: input=<a`b?> output=<a`b?> expect=<>
268: failed: input=<a`b?c> output=<a`b?c> expect=<c>
# COMP_WORDBREAKS='['$IFS
270: failed: input=<a`b[> output=<a`b[> expect=<>
271: failed: input=<a`b[c> output=<a`b[c> expect=<c>
# COMP_WORDBREAKS=']'$IFS
273: failed: input=<a`b]> output=<a`b]> expect=<>
274: failed: input=<a`b]c> output=<a`b]c> expect=<c>
# COMP_WORDBREAKS='^'$IFS
276: failed: input=<a`b^> output=<a`b^> expect=<>
277: failed: input=<a`b^c> output=<a`b^c> expect=<c>
# COMP_WORDBREAKS='_'$IFS
279: failed: input=<a`b_> output=<a`b_> expect=<>
280: failed: input=<a`b_c> output=<a`b_c> expect=<c>
# COMP_WORDBREAKS='}'$IFS
282: failed: input=<a`b}> output=<a`b}> expect=<>
283: failed: input=<a`b}c> output=<a`b}c> expect=<c>
# COMP_WORDBREAKS='~'$IFS
285: failed: input=<a`b~> output=<a`b~> expect=<>
286: failed: input=<a`b~c> output=<a`b~c> expect=<c>
# COMP_WORDBREAKS='`'$IFS
288: failed: input=<a`b`> output=<a`b`> expect=<>
I have put the test code that I used in gh790-test.sh
. You can download it and run it to perform the tests.
$ ./gh790-test.sh # test the implementation of PR #791
$ ./gh790-test.sh mug896 # test your implementation
I'm currently using bash version 5.1.16 Ubuntu 22.04.1 LTS There seems to be a lot of different values from the expected values. for example
. . .
285: failed: input=<a`b~> output=<a`b~> expect=<>
286: failed: input=<a`b~c> output=<a`b~c> expect=<c>
288: failed: input=<a`b`> output=<a`b`> expect=<>
my simple value printing completion function outputs different than expected value. I also checked on google cloud shell terminal that use bash version 5.1.4(1)-release
. . .
(mine, google) (expect)
285: a`b~ expect=<>
286: a`b~c expect=<c>
288: a`b` expect=<>
Did you set COMP_WORDBREAKS
? As far as I try in Bash 5.1.0, 5.1.8, and 5.1.16 in Fedora 36, Bash produces empty results with those cases with the corresponding COMP_WORDBREAKS
.
I also tried Bash 5.1.4 in Google Cloud Shell, but the result is the same: