Description
Describe the bug
Certain completions turn off globbing with set -o noglob
, perform some operation, and then attempt to reset globbing back to its original state. See for example
bash-completion/bash_completion
Lines 758 to 763 in 36ceb27
Unfortunately if the user presses Ctrl+C in the middle of this then the reset code is never run and the shell is left with set -o noglob
in effect. This will likely be very disconcerting for the user. For instance, running ls *
reports ls: cannot access *: No such file or directory
. That's the message you'd normally expect to see if the directory is empty but now you'll see it reported for all directories, giving the impression that all of your files have been deleted.
A user could recover from this by running set +o noglob
but they'd have to realize what was wrong first. I'm assuming in most cases people will just think their terminal is "broken" and be forced to close it and open a new one.
See also #691 .
To reproduce
You'll need a directory somewhere that's very slow to enumerate. One option would be to mount an NFS directory from some slow, distant machine. Another would be to create a local directory with an absurdly large number of files in it and have a cold cache (possibly something like echo 3 > /proc/sys/vm/drop_caches
might help on Linux). Or maybe https://serverfault.com/a/954175. I can personally reproduce this with a large directory on NFS.
# Verify that globbing is turned on to start
$ shopt -po noglob
set +o noglob
$ cd /path/to/your/directory/<TAB><Ctrl+C>
# Globbing is now unexpectedly turned off
$ shopt -po noglob
set -o noglob
Expected behavior
The noglob
setting should retain the previous value.
Versions (please complete the following information)
- Operating system name/distribution and version: CentOS Linux release 7.9.2009 (Core)
- bash version,
echo "$BASH_VERSION"
: 4.2.46(2)-release - bash-completion version,
(IFS=.; echo "${BASH_COMPLETION_VERSINFO[*]}")
: This command outputs "2.11.0", but I'm actually using git commit 36ceb27.
Additional context
Maybe this could be handled by running the compgen in a subshell so that the setting would not have to be remembered and then explicitly restored?
Debug trace
I'm going to avoid including entire thing for now since it is large and I don't think it will help explain the problem. If you still need it, please tell me and I'll send the full one. It ends with this, the compgen
having been interrupted by Ctrl+C:
+ local -a toks
+ local reset arg=-d
+ [[ -d == -d ]]
++ shopt -po noglob
+ reset='set +o noglob'
+ set -o noglob
+ toks=($(compgen -d -- "${cur-}"))
++ compgen -d -- /path/to/your/directory/
^C
$
I can't reproduce the problem on a different system that uses bash 5.1. I believe that's because of a recent change to bash, introduced in v5.1, that masks SIGINT during the execution of compgen
: https://github.com/bminor/bash/blob/9439ce094c9aa7557a9d53ac7b412a23aa66e36b/subst.c#L6542. This makes the code in bash-completion work as expected but has the downside that you can't abort the completion and have to wait for it to finish no matter how long it takes.