The list in complete -W list
is interpreted as a $IFS
delimited list, and it's the $IFS
at the time of completion that is taken into account.
So if you have:
complete -W 'a b,c d' do_work
do_work
completion will offer a
, b,c
and d
when $IFS
contains space and a b
and c d
when $IFS
contains ,
and not space.
So it's mostly broken by design. It also doesn't allow offering arbitrary strings as completions.
With these limitations, the best you can do is assume $IFS
will never be modified (so will always contain space, tab and newline, characters that as a result can't be used in the completion words), and do:
choices='foo bar baz'
do_work() {
case "$1" in
(*' '*) echo 'no!';;
(*)
case " $choices " in
(*" $1 "*) echo 'yes!';;
(*) echo 'no!';;
esac;;
esac
}
complete -W "$choices" do_work
You could add a readonly IFS
to make sure $IFS
is never modified, but that's likely to break things especially considering that bash
doesn't let you declare a local variable that has been declared readonly in a parent scope, so even functions that do local IFS=,
would break.
As for the more generic question of how to check whether a string is found amongst the elements of an array, bash
(contrary to zsh) doesn't have an operator for that but, you could easily implement it with a loop:
amongst() {
local string needle="$1"
shift
for string do
[[ $needle = "$string" ]] && return
done
false
}
And then:
do_work {
if amongst "$1" "${choices[@]}"; then
echo 'yes!'
else
echo 'no!'
fi
}
The more appropriate structure to look-up strings is to use hash tables or associative arrays:
typeset -A choices=( [foo]=1 [bar]=1 [baz]=1 )
do_work() {
if [[ -n ${choices[+$1]} ]]; then
echo 'yes!'
else
echo 'no!'
fi
}
complete -W "${!choices[*]}" do_work
Here with "${!choices[*]}"
joining the keys of the associative array with whichever is the first character of $IFS
at that point (or with no separator if it's set but empty).
Note that bash associative arrays can't have an empty key, so the empty string can't be one of the choices, but anyway complete -W
wouldn't support that either and completing an empty strings is not very useful anyway except maybe for the completion listing showing the user it's one of the accepted values.
The ‘|’ is used to separate multiple patterns
, so it is not part of the pattern itself – vatosarmat Sep 02 '22 at 08:07