92

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/?

6 Answers 6

56

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.

7
  • 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. Nov 2, 2016 at 18:41
  • 5
    @NobleUplift Bash Completion FAQ 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, 2019 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 :( Jan 21, 2019 at 17:47
  • @NobleUplift why? You can use them for yourself anyway.
    – jarno
    Jan 26, 2019 at 14:18
  • 2
    Whilst this answer still works due to backwards compatibility in /usr/share/bash-completion/bash_completion, it is deprecated in favour of this answer, 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, 2022 at 3:55
80

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.

2
  • 1
    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 4, 2022 at 7:49
  • 1
    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, 2022 at 15:21
30

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".)

9

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

1
  • 2
    Note that ~/.bash_completion is also configurable with $BASH_COMPLETION_USER_FILE
    – MestreLion
    Jun 10, 2022 at 15:24
6

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
1
  • 2
    FYI, an explanation of (or link to docs) about something being shown (i.e. nullglob) is helpful to the reader.
    – Cometsong
    Feb 25, 2019 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .