Believe it might be better to use compgen
instead of find
in this case.
You probably already have a completion script with system. Try e.g.
locate bash_completion
On Debian variants this is probably:
/usr/share/bash-completion/bash_completion
where you find e.g. _filedir
. So the simplest way then would be something in the direction of:
*)
pushd "/some/path" >/dev/null
_filedir
popd >/dev/null
If that is not an option this could be a starter:
_comp_by_path()
{
local opt cur dir
local IFS=$'\n' x tmp
local -a tokens
opt="$1"
cur="$2"
dir="$3"
# Enter target directory
pushd "$dir" >/dev/null
# Get directories, filtered against current
[[ "$opt" != "-f" ]] && \
x=$( compgen -d -- "$cur" ) &&
while read -r tmp; do
tokens+=( "$tmp" )
done <<< "$x"
# Get files, filtered against current
[[ "$opt" != "-d" ]] && \
x=$( compgen -f -- "$cur" ) &&
while read -r tmp; do
tokens+=( "$tmp" )
done <<< "$x"
# If anything found
if [[ ${#tokens[@]} -ne 0 ]]; then
# Make sure escaping is OK
compopt -o filenames 2>/dev/null
COMPREPLY+=( "${tokens[@]}" )
fi
# Go back
popd >/dev/null
}
_GetOptMyCommand()
{
local cur
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "-h -l --help --list --" -- "$cur" ) );;
*)
_comp_by_path "any" "$cur" "/some/path"
esac
}
complete -F _GetOptMyCommand my_command
A variant using find
could be something in direction of this:
_zaso()
{
local dir="$1"
pushd "$dir" >/dev/null
find * -maxdepth 0 2>/dev/null
popd >/dev/null
}
_comp_with_find()
{
local cur dir
local IFS=$'\n'
cur="$1"
dir="$2"
compopt -o filenames 2>/dev/null
COMPREPLY=( $( compgen -W "$(_zaso "$dir")" -- "$cur" ) );
}
Also note that printf
in Bash has a %q
option. So to generate quoted strings this is an option to play with:
find * -maxdepth 0 2>/dev/null && \
while read -r tmp; do
printf "%q\n" "$tmp"
done <<< "$x"
Also not that file names can have newline characters in which a lot of this will break. Have not found a way to use \0
with compgen
.
Best Answer
Yes, it is possible to implement path-completion from a custom base-directory specified by a command-line option-flag. Here is a small example illustrating how to accomplish this. First I'm going to slightly modify your example script to make the demonstration slightly more interesting (i.e. to produce output):
This is essentially the same as your example script, but it prints out the given argument.
Next we need to write a function to be called by the Bash programmatic-completion system. Here is a script which defines such a function:
Now let's source our completion script:
Let's make our script executable and move it to somewhere in our PATH:
And finally, let's add an alias for our script which doesn't have a file extension:
Now if you enter
echo -d
and hit the tab button then you should get file-path completion starting from the BASE_DIRECTORY. To test this out you could try the following:When you hit tab you should get the following list of completions:
Notice that after the first tab the string is converted to an absolute path. You can change this if you want, but I think this is might be the preferable behavior.
Here are some references you can consult for more information.
For official references, take a look at following sections of the Bash manual:
Section: 5.2 Bash Variables (look for variables with the
COMP_
prefix)Section 8.7: Programmable Completion Builtins
Also look at the Advanced Bash Scripting Guide from the Linux Documentation Project:
For a quick introduction to some features of programmatic completion in Bash, see this post from "The Geek Stuff" site:
There are also several related StackOverflow posts that you might find useful:
Custom Bash Autocomplete with File Path Completion
specify another directory to compgen for auto completing directories, than using pwd
Bash tab completion adds extra space after the first completion
Conditional trailing space with bash programmable completion