You can customize Bash auto-completion by defining a completion function that reads options from a text file and registers it with the
complete command. This approach allows dynamic updates to available commands without modifying the script itself, provided the text file is properly formatted and the shell source configuration correctly.
Understanding Bash Completion Functions
Bash uses a specific mechanism called "completion functions" to determine what suggestions to offer when you press the Tab key. These functions are standard shell functions that return a list of possible completions via the
COMPREPLY array variable. When you create a custom completion for a script or command, you are essentially writing a function that parses the current word being typed and suggests matches. For simple cases involving a static list of options stored in a file, this process becomes quite straightforward. The core requirement is that your function must populate
COMPREPLY with an array of strings that match the user's input prefix.
Preparing the Text File
The foundation of this customization is the text file itself. It should contain one option per line, with no extra whitespace or special characters that might interfere with parsing. For example, if you are creating autocomplete for a deployment tool, your file might look like this:
deploy-staging
deploy-production
rollback-v1
rollback-v2
status-check
restart-service
Ensure the file is readable by the user running the shell. If the file is located in a non-standard directory, you must provide the full path in your script. It is also advisable to keep the file in a consistent location, such as
~/.config/myapp/options.txt, so that the completion script can reliably find it. Avoid using commas or other delimiters; line breaks are the standard separator for this method because they are easily handled by shell utilities like
grep or
while read loops.
Writing the Completion Function
The next step is to write the shell function that will act as the completion handler. This function needs to perform three main tasks: extract the current word being typed, filter the options from the text file based on that word, and assign the results to
COMPREPLY. Here is a robust template for such a function:
my_custom_completion() {
local cur="${COMP_WORDS[COMP_CWORD]}"
local opts_file="$HOME/.config/myapp/options.txt"
# Read all lines from the file into an array
mapfile -t all_opts < "$opts_file"
# Filter options that start with the current word
COMPREPLY=($(compgen -W "${all_opts[*]}" -- "$cur"))
}
In this code,
${COMP_WORDS[COMP_CWORD]} retrieves the word currently being edited by the user. The
mapfile command (also known as
readarray) loads each line of the text file into the
all_opts array. Finally,
compgen -W generates completions from the word list that match the prefix
$cur. This method is efficient because it leverages built-in Bash tools rather than spawning external processes for every keystroke.
Registering the Completion
Once the function is defined, it must be registered with Bash using the
complete builtin. This tells Bash to call your function whenever the specified command is invoked. Assuming your script is named
myapp, you would add the following line to your
~/.bashrc or
~/.profile:
complete -F my_custom_completion myapp
After adding this line, you need to reload your shell configuration by running
source ~/.bashrc. From then on, typing
myapp [Tab] will trigger your custom function. This registration step is critical; without it, Bash will not know to use your custom logic instead of default filename completion. Note that if you change the text file while the shell is active, you do not need to re-source the config, as the function reads the file at runtime. However, changes to the function definition itself require a shell restart or re-sourcing.
Troubleshooting Common Issues
If your autocomplete does not work, check the permissions of the text file and ensure the path in the function is correct. A common mistake is forgetting to quote variables, which can cause word splitting issues if filenames contain spaces. Additionally, verify that the
complete command is associated with the exact name of the executable. If you are testing this in a subshell or a different environment, ensure that the
~/.bashrc modifications have been applied. You can debug the function by calling
my_custom_completion manually after setting
COMP_WORDS and
COMP_CWORD variables artificially, though this is rarely necessary for simple text-file-based completions. For more complex scenarios involving arguments, consider exploring how to handle flags and positional parameters separately.
Frequently Asked Questions
Can I use multiple text files for different categories?
Yes, you can modify the function to read from different files based on the context or arguments provided. You would simply add logic to check
COMP_WORDS for specific flags and select the appropriate file path before filtering.
Does this work in Zsh or Fish shells?
No, this specific syntax relies on Bash-specific variables like
COMP_WORDS and the
complete builtin. Other shells have their own completion systems, such as Zsh's
_arguments or Fish's declarative completions.
How do I handle options with spaces in them?
The
compgen -W approach handles spaces correctly if the words are properly quoted in the array. Ensure that your text file does not introduce unintended word splitting by using
mapfile which preserves line breaks exactly as they appear.
Can I make the completion case-insensitive?
By default, Bash completion is case-sensitive. To make it case-insensitive, you can set the
shopt -s nocaseglob option in your shell configuration, or modify the completion function to convert both the input and the options to lowercase before comparison.
What happens if the text file is empty?
If the file is empty, the
all_opts array will be empty, and
compgen will return nothing. This means no suggestions will appear, which is the expected behavior. It is good practice to add a fallback message or default options in your function if the file might be missing.