5

I have found that shopt -s nullglob apparently disables tab-completion for files and directories, and shopt -u nullglob restores it. Why does tab-completion for directories apparently rely on nullglob being unset?

I am using Bash 4.2.37(1)-release on Debian 7.

codeforester
  • 39,467
  • 16
  • 112
  • 140
Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
  • I don't see that here. What version of bash? What distribution? What command are you testing this with? – Etan Reisner Apr 27 '15 at 23:50
  • @EtanReisner Various commands--builtins such as `echo`, programs such as `ls`, aliases....I don't think it matters, since tab-completion for paths is not command-specific. I've added my Bash version and Linux distro to the question. – Kyle Strand Apr 27 '15 at 23:56
  • 1
    Tab completion is command specific actually (see the output from `complete` for more about that). You can easily break completion for a specific command without breaking completion in general. – Etan Reisner Apr 28 '15 at 01:41
  • I see this on my debian machine also but not on my CentOS 5 machine. – Etan Reisner Apr 28 '15 at 01:46
  • The problem seems to be in the `__reassemble_comp_words_by_ref` function but I don't understand what is happening yet. – Etan Reisner Apr 28 '15 at 01:48
  • @EtanReisner Tab completion in general is command-specific, but I thought the specific completion function used for *file paths* is *not* command-specific--right? – Kyle Strand Apr 28 '15 at 04:03
  • That's true. The completion of files and directories itself is not command specific but the support for what completions are done for a given command is (and how that completion is done) so it would be entirely possible to break the specific completion function used by the `garble` command while leaving the completion function used by `bargle` alone. – Etan Reisner Apr 28 '15 at 11:20

1 Answers1

3

This is apparently a known issue with bash-completion and is listed as an objective to be fixed in the 3.0 version.

But apparently it has been that way since at least 2012.

See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666933 for reference.

Edit: At least 2011: http://thread.gmane.org/gmane.comp.shells.bash.completion.devel/3652

I do not at all understand how nullglob causes the problem listed in that email though.

Edit: I now understand what is happening. The problem is that glob expansion is dumb. It sees the entire "word" $2[$j]=\${!ref}\${COMP_WORDS[i]} as a single glob and tries to expand it. Normally that fails and it gets left alone but will nullglob on that entire argument simply vanishes (thus causing the problem).

Quick testing indicates that replacing this:

eval $2[$j]=\${!ref}\${COMP_WORDS[i]}

with either:

eval $2\[$j\]=\${!ref}\${COMP_WORDS\[i\]}

or:

eval "$2[$j]=\${!ref}\${COMP_WORDS[i]}"

seems to fix the problem. I can't vouch for either of those being a fully correct fix though.

Update: This is fixed in the debian bash-completion git repository already (in a way I hadn't thought of but which is clearly better).

This commit fixes it. There are other globbing related fixes too.

Grabbing the __reassemble_comp_words_by_ref from git head and sourcing that on top of the current one appears to fix the problem as a temporary workaround/solution.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • 1
    I agree. What's more disappointing is that I couldn't see anyone discussing what the problem might actually be. I'm tempted to take the report from that second link and post it as an SO question to see if anyone can explain what's happening there since I don't understand it. – Etan Reisner Apr 28 '15 at 11:18
  • I've seen a number of cases (I think some in the git completion code) that break because it's trying to use glob's default behavior without realizing that nullglob is set. nullglob is *better* in a number of ways, but there's nothing wrong with some code using old-style-yields-the-wildcard-back-on-fail IF the code locally sets nullglob off, and restores it after. Which isn't what was happening. The result would be similar to how IFS is used in similar cases. – Alex North-Keys Aug 05 '15 at 14:54
  • Prompted to look at this again I see now why things are getting confused. The shell is treating the `$2[$j]=\${!ref}\${COMP_WORDS[i]}` line from the completion code as a glob (because of the `[]` brackets) and simply expanding the entire string away. Without `nullglob` on the shell leaves it alone (as a failing expansion). That's certainly surprising behavior to my mind. In a quick manual test escaping both sets of `[]` on that line (and the one after the loop) fixes the problem. As does quoting the entire argument to `eval`. – Etan Reisner Aug 18 '15 at 03:44