81

I have user access (no root) into a Linux (Suse) machine where I developed some bash scripts and the corresponding bash autocompletion rules.

Since the scripts belong only to my user and therefore I need the complete rules only "active" for me (a part from the fact that I have no root write acces), placing my bash_completion script into /etc/bash_completion.d/ folder is not an option.

At the moment I named my file .bash_completion.myscript and source it directly from my .bashrc, but I just wonder if there is any other "standard" way of achieving these results, already considered in the bash implementation.

For example, creating a folder /home/myuser/.bash_completion.d/?

HopelessN00b
  • 53,385
  • 32
  • 133
  • 208
Carles Sala
  • 913
  • 1
  • 7
  • 6

6 Answers6

76

For non-XDG environments and bash-completion <= 2.8

Here is how a local user can have a working ~/.bash_completion.d/ directory.

  1. edit file: nano ~/.bash_completion, add the following:
for bcfile in ~/.bash_completion.d/* ; do
  . $bcfile
done
  1. make directory: mkdir ~/.bash_completion.d
  2. edit file: ~/.bash_completion.d/myscript, add the following:
_myscript_tab_complete () {
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    words="-f -h --etc"

    COMPREPLY=( $(compgen -W "${words}" -- ${cur}) )
    return 0
}
complete -F _myscript_tab_complete myscript
  1. source .bash_completion: . ~/.bash_completion

anticipating empty ~/.bash_completion.d/ directory

If you anticipate having an empty ~/.bash_completion.d/ directory, and want to avoid seeing the error message bash: /home/<username>/.bash_completion.d/*: No such file or directory, add a file type test with [ -f "$bcfile" ].

for bcfile in ~/.bash_completion.d/* ; do
  [ -f "$bcfile" ] && . $bcfile
done

For XDG environments & bash-completion <= version 2.8

(To see your version: rpm -qa | grep bash-completion)

Note that bash-completion 2.8 README documentation still recommends ~/.bash_completion, See https://github.com/scop/bash-completion/tree/2.8

You know your linux environment is XDG if xdg-usr-dir command exists and returns your home directory, and your environment variables include XDG_*; execute: env | grep XDG.

For XDG environment & bash-completion >= version 2.9

According to the bash-completion README starting in version 2.9 https://github.com/scop/bash-completion/tree/2.9 (April 27, 2019) there is now recognized a working local user bash_completion directory. Additionally an alternate bash_completion config file has already been supported for several previous releases.

  • ~/.bash_completion.d -> ${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion
  • ~/.bash_completion -> ${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion

To implement with this configuration, complete the previous steps 3,4 above using $XDG_DATA_HOME/bash-completion - you should not modify $XDG_CONFIG_HOME/bash_completion as described in step 1, but you may need to create the $XDG_DATA_HOME/bash-completion directory.

Note: As of CentOS 8.2 and Fedora 32, bash-completion <= 2.8 is installed.

Russell E Glaue
  • 921
  • 7
  • 7
  • I would like to add that on my box (`RHEL8.5`, `bash-completion-2.7-5.el8`, non-XDG), scripts under `~/.local/share/bash-completion/completions` are sourced automatically without additional configuration, so this answer's classification may not be entirely accurate. I recommend you (the reader) to always test these newer standard directories regardless of what version you have installed. – cyqsimon Apr 04 '22 at 07:49
  • Very detailed answer, but some inaccuracies: `~/.local/share/bash-completion/completions` dir for dynamic, lazy-loading completions has been around since v2.2, from 2016. `~/.bash_completion` file is for static, eager loading, and thus **not** recommended. And that path is configurable via `BASH_COMPLETION_USER_FILE` since v2.7 from 2017. – MestreLion Jun 10 '22 at 15:21
48

Use a ~/.bash_completion file.

From the Bash Completion FAQ:

Q. How can I insert my own local completions without having to
reinsert them every time you issue a new release?

A. Put them in ~/.bash_completion, which is parsed at the end of the
main completion script. See also the next question.

Q. I author/maintain package X and would like to maintain my own
completion code for this package. Where should I put it to be sure
that interactive bash shells will find it and source it?

A. Install it in one of the directories pointed to by
bash-completion's pkgconfig file variables. There are two
alternatives: the recommended one is 'completionsdir' (get it with
"pkg-config --variable=completionsdir bash-completion") from which
completions are loaded on demand based on invoked commands' names,
so be sure to name your completion file accordingly, and to include
for example symbolic links in case the file provides completions
for more than one command. The other one which is present for
backwards compatibility reasons is 'compatdir' (get it with
"pkg-config --variable=compatdir bash-completion") from which files
are loaded when bash_completion is loaded.

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • 4
    Might want to specify that `.bash_completion` is a file and not a directory. Since `bash_completion.d` is a directory I assumed I could just `scp` my local `bash_completion.d` and rename it on the remote server, but on the next login it told me it had to be a file. – NobleUplift Nov 02 '16 at 18:41
  • 3
    @NobleUplift [Bash Completion FAQ](https://github.com/scop/bash-completion/blob/master/README.md) has changed and now contains information about a way for loading the user's Bash completions from a directory on demand. This seems to work by bash-completion version 2.8 at least, but not by 2.1. The files in the directory should be named exactly like the command they are for, or symbolic links could be used for that purpose. – jarno Jan 20 '19 at 12:06
  • 1
    @jarno I coded bash completion scripts for all the custom programs and scripts in our system but my senior developers shot them down :( – NobleUplift Jan 21 '19 at 17:47
  • @NobleUplift why? You can use them for yourself anyway. – jarno Jan 26 '19 at 14:18
  • @jarno Actually I am still using a few of the completion scripts, but it saps the motivation to make completion scripts for the scripts I seldom ever use and the benefit of others if they'll never be used. – NobleUplift Jan 30 '19 at 22:54
  • After reading the main completion script, /etc/bash_completion.d/ is tested and if exists reading file inside – Leahkim Jun 08 '21 at 15:29
  • Whilst this answer still works due to backwards compatibility in `/usr/share/bash-completion/bash_completion`, it is deprecated in favour of [this answer](https://serverfault.com/a/1013395/102407), where the autocomplete script for the command `myscript` would be saved to `~/.local/share/bash-completion/completions/myscript` (the tail can also be `myscript.bash` or `_myscript`). This way your scripts are organised and only loaded dynamically. – Walf Jul 26 '22 at 03:55
17

The FAQ has been updated. There is now a standard place for local completions.

Q. Where should I install my own local completions?

A. Put them in the completions subdir of $BASH_COMPLETION_USER_DIR (defaults to $XDG_DATA_HOME/bash-completion or ~/.local/share/bash-completion if $XDG_DATA_HOME is not set) to have them loaded on demand. See also the next question's answer for considerations for these files' names, they apply here as well. Alternatively, you can write them directly in ~/.bash_completion which is loaded eagerly by our main script.

  1. If it does not exist, create a directory at ~/.local/share/bash-completion/completions (or $XDG_DATA_HOME/bash-completion/completions).
$ mkdir -p ~/.local/share/bash-completion/completions
  1. Put your completions in the new directory.
$ cp <your_completions_file> ~/.local/share/bash-completion/completions

Note the that completions file should have the same name as the command that it is providing completions for. (e.g. The completions file for git should be called "git".)

hallidave
  • 291
  • 2
  • 4
8

At least bash-completion 2.8 and later enable option to place local Bash completions in directory

${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions

The completion file names or symbolic link names must match the respective command names. These completions are loaded only on demand. Completions stored in file ~/.bash_completion are loaded always.

Reference: See "Q. Where should I install my own local completions?" in https://github.com/scop/bash-completion/blob/master/README.md

jarno
  • 183
  • 1
  • 7
5

A simpler solution is to use the nullglob option. While this isn't portable, neither are bash completions. So portability doesn't matter.

Also, you'll want to use quotes around the variable when sourcing. This handles the case where the file has spaces other other special characters.

shopt -s nullglob

for f in ~/.bash_completion.d/*; do
  [ -f "$f" ] && . "$f"
done
npmccallum
  • 51
  • 1
  • 1
  • 1
    FYI, an explanation of (or link to docs) about something being shown (i.e. `nullglob`) is helpful to the reader. – Cometsong Feb 25 '19 at 20:08
3

The answer by Russell E Glaue is great but its ~/.bash_completion is incomplete.

The problem is when ~/.bash_completion.d/ is empty and subsequently for f in ~/.bash_completion.d/* prints the following error message:

-bash: /home/user/.bash_completion.d/*: No such file or directory

The simplest, portable solution is to skip the loop if the directory is empty:

if [[ -d ~/.bash_completion.d/ ]] && \
   ! find ~/.bash_completion.d/. ! -name . -prune -exec false {} +
then
    for f in ~/.bash_completion.d/*
    do
        source "$f"
    done
fi