I\'m having a problem with bash-completion when the possible options may contain spaces.
Let\'s say I want a function which echoes the first argument:
fu
Okay, this crazy contraption draws heavily on rici’s solution, and not only fully works, but also quotes any completions that need it, and only those.
pink() {
# simulating actual awk output
echo "nick mason"
echo "syd-barrett"
echo "david_gilmour"
echo "roger waters"
echo "richard wright"
}
_test() {
cur=${COMP_WORDS[COMP_CWORD]}
mapfile -t patterns < <( pink )
mapfile -t COMPREPLY < <( compgen -W "$( printf '%q ' "${patterns[@]}" )" -- "$cur" | awk '/ / { print "\""$0"\"" } /^[^ ]+$/ { print $0 }' )
}
complete -F _test test
So as far as I could test it, it fully implements ls
-like behavior, minus the path-specific parts.
Here’s a more verbose version of the _test
function, so it becomes a bit more understandable:
_test() {
local cur escapedPatterns
cur=${COMP_WORDS[COMP_CWORD]}
mapfile -t patterns < <( pink )
escapedPatterns="$( printf '%q ' "${patterns[@]}" )"
mapfile -t COMPREPLY < <( compgen -W "$escapedPatterns" -- "$cur" | quoteIfNeeded )
}
quoteIfNeeded() {
# Only if it contains spaces. Otherwise return as-is.
awk '/ / { print "\""$0"\"" } /^[^ ]+$/ { print $0 }'
}
None of this is even remotely optimized for efficiency. Then again, this is only tab completion, and it’s not causing a noticeable delay for any reasonably large list of completions.
awk
output into an array, using mapfile
.%q
as a separation marker.$cur
, Very important!compgen
. And only if it contains spaces.mapfile
call.-o filenames
.And it only works with all those tricks. It fails if even a single one is missing. Trust me; I’ve tried. ;)