When using tab completion in bash, the $_ variable is altered:

$ mkdir test
$ cd <TAB><TAB> $_
bash: cd: -d: invalid option
cd: usage: cd [-L|[-P [-e]]] [dir]

(The <TAB><TAB> will list all files in current directory, but I don't end up using the output and write $_ instead. The command executed in this line will just be cd $_.)

Expected behavior would be to change into ./test.

How can I prevent bash completion from altering $_?

  • 3
    bash is pretty limited with its autocompletion options: I am not sure if that is possible. If you need more powerfull and customisable autocompletion in interactive session I suggest moving to zsh if that is possible. – IBr Oct 12 '13 at 9:10
  • 4
    This is almost certainly due to programmable completion, the default (readline) completion doesn't do this. Please indicate which version of bash, which completion package and/or the output of complete -p. – mr.spuratic Oct 12 '13 at 9:55
  • cd <TAB><TAB> should give you all possible completions (the 2nd tab),how are you entering $_? – terdon Oct 12 '13 at 14:03
  • @mr.spuratic Bash version is GNU bash is version 4.2.45(2)-release on x86_64. The output of complete -p is here: js.f0i.de/complete-p.html – f0i Oct 13 '13 at 14:53

You're using the bash-completion package (or a derivative). For each argument completion of the cd command (as shown by the complete -p output):

complete -o nospace -F _cd cd

the _cd function is invoked to determine the completions (slightly edited for brevity):

    local cur prev words cword
    _init_completion || return

    local IFS=$'\n' i j k

    compopt -o filenames

    if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then
        _filedir -d
        return 0

So for example, when you complete on a directory with no CDPATH set, the last-seen argument to a command seen is -d, and this is placed automatically in _. There are several other code paths in that function with similar side-effects.

Since _ is a bash internal, a conventional save/restore (as for IFS) won't work as hoped. You could do it with a little trickery:

    local save_="$_"
    : $save_
    return 0

You must save _ immediately on entry to a function, : is the null command, which does nothing per-se but has the usual side-effects of a command, such as setting _. This restore operation will be required for each return point of each potentially disruptive function. There's a subtlety here too: normally _ is set immediately after a return from a function (to the last argument of the function call, as expected), which would make this method ineffective. But, this doesn't happen when a completion function is invoked, since it's not explicit invoked. I don't consider this to be very robust...

(I prefer history expansion, and stick to !$ which doesn't suffer this problem.)

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.