Bash Автозаполнение - как передать этот массив для сжатия без значительного пробела, который рушится?

Следующее завершение bash передает массив возможных слов (например, завершений) для compgen.

basenames=("foo" "fu bar" "baz");

COMPREPLY=($(compgen -W "${basenames[*]}" -- "${COMP_WORDS[COMP_CWORD]}"))

Проблема заключается в том, что пробелы в элементах массива не сохраняются, то есть "foo bar" рассматривается как элемент благодаря разбиению слов. Есть ли способ сохранить пробелы, так что отображаются 3 элемента, а не 4?

ИЗМЕНИТЬ

basenames содержит имена файлов, то есть почти каждый символ (кроме/и\0) разрешен.

РЕДАКТИРОВАТЬ 2

Флаг -W ожидает одно слово, что-то вроде foo bar foobar. Передача ему нескольких элементов (это то, что будет делать ${basenames[@]}) не будет работать.

РЕДАКТИРОВАТЬ 3

Изменен массив базовых имен (так что foo и foo from foo bar не будут свернуты).

Использование новой строки для разделения слов работает:

local IFS=$'\n'
COMPREPLY=($(compgen -W "$(printf "%s\n" "${basenames[@]}")" --  ${COMP_WORDS[COMP_CWORD]}"))

Использование \0 не выполняет:

local IFS=$'\0'
COMPREPLY=($(compgen -W "$(printf "%s\0" "${basenames[@]}")" --  ${COMP_WORDS[COMP_CWORD]}"))

Ответ 1

Зачем беспокоиться compgen? Просто добавьте их в COMPREPLY вручную. Следующее выполнит соответствующие имена файлов из /some/path, безопасно обрабатывая имена файлов.

some_completion_function() {
    local files=("/some/path/$2"*)
    [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]##*/}" )
}

Невозможно иметь compgen имя файла для записи безопасно.

Ответ 2

Возможно, это может сделать:

COMPREPLY=($(compgen -W "$(printf "%q " "${basenames[*]}")" -- "${COMP_WORDS[COMP_CWORD]}"))

Ответ 3

Вы должны почти всегда использовать знак at вместо звездочки для индексирования массива.

COMPREPLY=($(compgen -W "${basenames[@]}" -- "${COMP_WORDS[COMP_CWORD]}"))

из man bash (или см. справочное руководство Bash):

Если индекс @ или *, слово расширяется для всех членов имени. Эти индексы отличаются только тогда, когда слово появляется в двойных кавычках. Если слово double-quoted, ${name[*]} расширяется до одного слова со значением каждого элемента массива, разделенным первым символом специальной переменной IFS, а ${name[@]} расширяет каждый элемент имени до отдельного слова.

Другими словами, знак знака "выравнивает" массив. Форма звездочки сохраняет его.