5

If I have the following files in a directory:

$ ls
a-file-1
b-file-2
something-else

And I type

$ cat *file*<TAB>

The line unexpectedly updates to

$ cat a-file-1 |

(pipe denotes cursor) even though the glob also matches b-file-2. A bit stranger is if I start another shell, I instead get a match listing on double-TAB (which I prefer):

$ cat *file*<TAB><TAB>
a-file-1  b-file-2
$ cat *file*|

Q: How is this behavior configured? I'd like to have the second behavior in the login shell.

It seems login shells are getting the first behavior, non-login shells are getting the second. However, my ~/.bash_profile does little more than kick off ~/.bashrc. (I don't have a .profile.) It seems somewhere somehow I must be changing the configuration.

The shopt differences are that only the login shell has extglob on, hostcomplete off, and login_shell on but changing these doesn't alter the above behavior. set -o output is the same. Tried set show-all-if-ambiguous on but that had no effect. I'm using Ubuntu 14.04.1.

Update regarding comment by @mpy.

In a non-login shell, when I include a base directory in the glob and press Alt-G, the behavior is different than when I use TABTAB. It's this specific latter behavior I want to configure in the login shell.

Alt-G:

$ ls dir/*file*<Alt-G>

updates to

$ ls dir/|

removing the glob and not printing any matches. Whereas TABTAB outputs the matches

$ ls dir/*file*<TAB><TAB>
a-file-1  b-file-2
$ ls dir/*file*|
2
  • Please check if your key bindings are differing (bind -P). I can reproduce the behaviour of your login shell. But using Alt-G (glob-complete-word) instead of TAB (complete) I get the second behaviour.
    – mpy
    Oct 12, 2014 at 10:06
  • @mpy thank you. Interesting but doesn't seem to be the cause. bind -P output from both shells are identical. Also, the behavior of glob-complete-word is a little different than what I'm seeing in the non-login shell with TAB-TAB. I've updated my answer to explain.
    – G-Wiz
    Oct 14, 2014 at 3:32

2 Answers 2

3

In Ubuntu 14.04, I get the horrible first-match expansion behaviour by default, but I think it's the fault of something in the programmable completion.

After a shopt -u progcomp, I get the nice list-expansions behaviour.

Your login vs non-login shell behaviour is probably due to getting .bash_profile and /etc/profile, or not. (Or your login shell NOT getting /etc/bash.bashrc or .bashrc, if your profile doesn't source it/them.)

update: tracked down the bug in the programmable completion: turned on set -x, and looked at the output of all the commands that were run after hitting TAB. Found where the glob expression turned into a list, and found that in /usr/share/bash-completion/bash_completion

The problem was here: (search for xspec to find these lines)

xspec=${1:+"!*.@($1|${1^^})"}
x=$( compgen -f -X "$xspec" -- "$quoted" ) &&

"$quoted" was missing quotes, so it was getting expanded there, in the completion-processing shell functions. $quoted is used inside double quotes elsewhere in the script, so I'm pretty confident it's supposed to be quoted, and that was the right way to fix this.

reported as https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/1387057, will hopefully get fixed upstream and make its way into all distros soon.

6
  • Adding shopt -u progcomp to .bashrc seems to have done the trick. It's strange because shopt hadn't reported that differently between my environments. Great find with the quoted bug.
    – G-Wiz
    Nov 29, 2014 at 16:22
  • 1
    shopt -u progcomp disables programmable completion... I was just saying that as a way to test if the behaviour was coming from programmable completion or not. Dec 2, 2014 at 14:53
  • Ah, thanks. bash baffles me. So if I keep progcomp enabled, and add the quotes to bash_completion, I get neither the first-match expansion, nor the list-expansions behavior. When I hit TAB (once or twice), nothing happens. However, if I execute bash, I get the list expansion on double TAB (but set -x yields nothing there, strangely). Do you have any further pointers?
    – G-Wiz
    Dec 3, 2014 at 5:25
  • 1
    oh, hmm, I hadn't noticed that bash without programmable completion had pretty nice behaviour with glob expressions. If you prefer that glob behaviour over progcom, then disable progcomp. progcomp gives you stuff like being able to tab-complete man ab[TAB] => comp on commands, or git c[TAB] => comp on git commands. And esp. sudo ifc[TAB] => complete on commands. Also stuff like find -[TAB] => complete on options. Many commands have smart handlers to sometimes save you a look at the man page. Dec 3, 2014 at 8:35
  • 1
    basically, there's 2 modes you can be in: programmable completion with all those shell functions loaded, or without that. Choose by sourcing /etc/profile.d/bash_completion, or not, from your ~/.bashrc or /etc/bash.bashrc. (can also disable after already loaded, with shopt -u progcomp, or complete -r.) Dec 3, 2014 at 8:38
3

In addition to the unquoted "$quoted" that @peter-cordes mentioned, there's another bug in the _filedir() function:

--- /usr/share/bash-completion/bash_completion--OLD 2015-08-19 19:58:22.734667377 -0500
+++ /usr/share/bash-completion/bash_completion      2016-01-05 15:56:50.442988910 -0500
@@ -604,6 +604,8 @@
         # 2>/dev/null for direct invocation, e.g. in the _filedir unit test
         compopt -o filenames 2>/dev/null
         COMPREPLY+=( "${toks[@]}" )
+    else
+        compopt -o bashdefault 2>/dev/null
     fi
 } # _filedir()

This lets you eat your cake and have it, too: you can keep your "shopt -s progcmp" bash_completion AND if that doesn't find a match, it will fall back to using bash's default glob-handling.

1
  • This is great! I guess I just need to watch out for updates to the bash-completion package.
    – G-Wiz
    Jan 5, 2016 at 22:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.