Bash completion for path in argument (with equals sign present)
I removed all bash completion scripts and started adding them one by one to if any of them cause the problem.
In my case it turned out to be the npm completion script was the cause of this problem.
Not sure (yet) what the problem is, but this is the completion script which caused equal sign values not working as before:
###-begin-npm-completion-###
#
# npm command completion script
#
# Installation: npm completion >> ~/.bashrc (or ~/.zshrc)
# Or, maybe: npm completion > /usr/local/etc/bash_completion.d/npm
#
COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
COMP_WORDBREAKS=${COMP_WORDBREAKS/@/}
export COMP_WORDBREAKS
if type complete &>/dev/null; then
_npm_completion () {
local si="$IFS"
IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
COMP_LINE="$COMP_LINE" \
COMP_POINT="$COMP_POINT" \
npm completion -- "${COMP_WORDS[@]}" \
2>/dev/null)) || return $?
IFS="$si"
}
complete -F _npm_completion npm
elif type compdef &>/dev/null; then
_npm_completion() {
si=$IFS
compadd -- $(COMP_CWORD=$((CURRENT-1)) \
COMP_LINE=$BUFFER \
COMP_POINT=0 \
npm completion -- "${words[@]}" \
2>/dev/null)
IFS=$si
}
compdef _npm_completion npm
elif type compctl &>/dev/null; then
_npm_completion () {
local cword line point words si
read -Ac words
read -cn cword
let cword-=1
read -l line
read -ln point
si="$IFS"
IFS=$'\n' reply=($(COMP_CWORD="$cword" \
COMP_LINE="$line" \
COMP_POINT="$point" \
npm completion -- "${words[@]}" \
2>/dev/null)) || return $?
IFS="$si"
}
compctl -K _npm_completion npm
fi
###-end-npm-completion-###
Bash Tab Completion of Filenames after Arguments
After googling (and help from friends) i've found the solution!
To fix filename auto completion add the following to your ~/.bashrc
file:
complete -D -o default
Reference: Bash completion for path in argument (with equals sign present)
How to reset COMP_WORDBREAKS without affecting other completion script?
Modifying $COMP_WORDBREAKS
in your completion script is not the recommended way (as it is a global variable and it could affect the behavior of other completion scripts - for example ssh).
However, bash completion offers some helper methods which you can use to achieve your goal.
The recommended way to handle non-word-breaking characters in completion words is by using the two helper methods:
_get_comp_words_by_ref
with the-n EXCLUDE
option- gets the word-to-complete without considering the characters in EXCLUDE as word breaks
__ltrim_colon_completions
- removes colon containing prefix from COMPREPLY items
(a workaround for http://tiswww.case.edu/php/chet/bash/FAQ - E13)
- removes colon containing prefix from COMPREPLY items
So, here is a basic example of how to a handle a colon (:) in completion words:
_mytool()
{
local cur
_get_comp_words_by_ref -n : cur
# my implementation here
COMPREPLY=( $(compgen ..........my_implement......... -- $cur) )
__ltrim_colon_completions "$cur"
}
complete -F _mytool mytool
As a final tip, the helper methods are located in /etc/bash_completion
. Take a look inside to read a detailed description of each method and to discover more helper methods.
python argparse autocompletion with file paths
For me using the equals sign ("=") after the argument name got the autocomplete to work and suggest all files matching the input path so far. For example, try:
python main.py -c=<your path>
When I didn't use the "=" sign the autocomplete worked only for folders and files ending with ".py" extension. The possible reason behind could be completion script installed for python. See here for more: https://www.reddit.com/r/bash/comments/b8oqeg/comment/ek1ds7t/?utm_source=share&utm_medium=web2x&context=3
Customizing bash completion output: each suggestion on a new line
bash
prior to version 4.2 doesn't allow any control over the output format of completions, unfortunately.
Bash 4.2+ allows switching to 1-suggestion-per-line output globally, as explained in Grisha Levit's helpful answer, which also links to a clever workaround to achieve a per-completion-function solution.
The following is a tricky workaround for a custom completion.
Solving this problem generically, for all defined completions, would be much harder (if there were a way to invoke readline
functions directly, it might be easier, but I haven't found a way to do that).
To test the proof of concept below:
- Save to a file and source it (
. file
) in your interactive shell - this will:- define a command named
foo
(a shell function) - whose arguments complete based on matching filenames in the current directory.
- (When
foo
is actually invoked, it simply prints its argument in diagnostic form.)
- define a command named
- Invoke as:
foo [fileNamePrefix]
, then press tab:- If between 2 and 9 files in the current directory match, you'll see the desired line-by-line display.
- Otherwise (1 match or 10 or more matches), normal completion will occur.
Limitations:
- Completion only works properly when applied to the LAST argument on the command line being edited.
- When a completion is actually inserted in the command line (once the match is unambiguous), NO space is appended to it (this behavior is required for the workaround).
- Redrawing the prompt the first time after printing custom-formatted output may not work properly: Redrawing the command line including the prompt must be simulated and since there is no direct way to obtain an expanded version of the prompt-definition string stored in
$PS1
, a workaround (inspired by https://stackoverflow.com/a/24006864/45375) is used, which should work in typical cases, but is not foolproof.
Approach:
- Defines and assigns a custom completion shell function to the command of interest.
- The custom function determines the matches and, if their count is in the desired range, bypasses the normal completion mechanism and creates custom-formatted output.
- The custom-formatted output (each match on its own line) is sent directly to the terminal
>/dev/tty
, and then the prompt and command line are manually "redrawn" to mimic standard completion behavior. - See the comments in the source code for implementation details.
# Define the command (function) for which to establish custom command completion.
# The command simply prints out all its arguments in diagnostic form.
foo() { local a i=0; for a; do echo "\$$((i+=1))=[$a]"; done; }
# Define the completion function that will generate the set of completions
# when <tab> is pressed.
# CAVEAT:
# Only works properly if <tab> is pressed at the END of the command line,
# i.e., if completion is applied to the LAST argument.
_complete_foo() {
local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount
# Collect matches, providing the current command-line token as input.
IFS=$'\n' read -d '' -ra matches <<<"$(compgen -A file "$currToken")"
# Count matches.
matchCount=${#matches[@]}
# Output in custom format, depending on the number of matches.
if (( matchCount > 1 && matchCount < 10 )); then
# Output matches in CUSTOM format:
# print the matches line by line, directly to the terminal.
printf '\n%s' "${matches[@]}" >/dev/tty
# !! We actually *must* pass out the current token as the result,
# !! as it will otherwise be *removed* from the redrawn line,
# !! even though $COMP_LINE *includes* that token.
# !! Also, by passing out a nonempty result, we avoid the bell
# !! signal that normally indicates a failed completion.
# !! However, by passing out a single result, a *space* will
# !! be appended to the last token - unless the compspec
# !! (mapping established via `complete`) was defined with
# !! `-o nospace`.
COMPREPLY=( "$currToken" )
# Finally, simulate redrawing the command line.
# Obtain an *expanded version* of `$PS1` using a trick
# inspired by https://stackoverflow.com/a/24006864/45375.
# !! This is NOT foolproof, but hopefully works in most cases.
expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}')
printf '\n%s%s' "$expandedPrompt" "$COMP_LINE" >/dev/tty
else # Just 1 match or 10 or more matches?
# Perform NORMAL completion: let bash handle it by
# reporting matches via array variable `$COMPREPLY`.
COMPREPLY=( "${matches[@]}" )
fi
}
# Map the completion function (`_complete_foo`) to the command (`foo`).
# `-o nospace` ensures that no space is appended after a completion,
# which is needed for our workaround.
complete -o nospace -F _complete_foo -- foo
How to obtain the absolute path of a file via Shell (BASH/ZSH/SH)?
Use realpath
$ realpath example.txt
/home/username/example.txt
What does export variable without an equals sign do?
The two lines of code (better to use double brackets):
[[ -r /etc/java/java.conf ]] && . /etc/java/java.conf
export JAVA_HOME
...equates to this:
-r
checks if /etc/java/java.conf
exists and read permission is granted.
&&
if the condition above is true then source the file.
export JAVA_HOME
takes the previously-assigned value of $JAVA_HOME
from the sourced file making it available to subprocesses rather than only within the shell.
- What does "export" do in shell programming?
- What does "source" do?
- Conditional statements in bash
Related Topics
How to Schedule an R Script Cronjob in a Linux Server
Difference Between Linux Kernel and Unix Kernel(Such as Freebsd) from Programmer's Point of View
"Cannot Write to Log File Pg_Upgrade_Internal.Log" When Upgrading from Postgresql 9.1 to 9.3
Explanation of Memcpy Memmove Glibc_2.14/2.2.5
How to Find Out Where Is My Code Causing Glib-Gobject-Critical
Erge Text Files Ordered by Numerical Filenames in Bash
How to Determine the Precise Set of Environment Variables a Systemd Environmentfile Would Set
How to Disassemble a System Call
Addresses of Thread Local Storage Variables
What Are Some Conditions That May Cause Fork() or System() Calls to Fail on Linux
Changing Pecl Installation Directory
Docker Oci Runtime Create Failed: Container_Linux.Go:349: Starting Container Process Caused
Is There an Scp Variant of Mv Command
How to Set Runpath of a Binary