Каков правильный/лучший способ обработки пробелов и кавычек в завершении bash?
Вот простой пример. У меня есть команда под названием words
(например, программа поиска словаря), которая принимает различные слова в качестве аргументов. Поддерживаемые слова могут содержать пробелы и определены в файле с именем words.dat
:
foo
bar one
bar two
Вот мое первое предлагаемое решение:
_find_words()
{
search="$cur"
grep -- "^$search" words.dat
}
_words_complete()
{
local IFS=$'\n'
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $( compgen -W "$(_find_words)" -- "$cur" ) )
}
complete -F _words_complete words
Ввод ‘words f<tab>’
корректно завершает команду ‘words foo ’
(с конечным пространством), что приятно, но для ‘words b<tab>’
она предлагает ‘words bar ’
. Правильное завершение будет ‘words bar\ ’
. И для ‘words "b<tab>’
и ‘words 'b<tab>’
он не предлагает никаких предложений.
Эта последняя часть, которую я смог решить. Его можно использовать eval
для правильного анализа (экранированных) символов. Однако eval
не любит отсутствующих котировок, поэтому, чтобы заставить все работать, мне пришлось изменить search="$cur"
на
search=$(eval echo "$cur" 2>/dev/null ||
eval echo "$cur'" 2>/dev/null ||
eval echo "$cur\"" 2>/dev/null || "")
Это действительно работает. Оба ‘words "b<tab>’
и ‘words 'b<tab>’
правильно автозаполняются, и если я добавлю ‘o’
и снова нажимаю <tab>
, он фактически завершает слово и добавляет правильную закрывающую цитату. Однако, если я попытаюсь завершить ‘words b<tab>’
или даже ‘words bar\ <tab>’
, он будет автозаполнен ‘words bar ’
вместо ‘words bar\ ’
, а добавление для примера ‘one’
завершится с ошибкой при запуске программы words
.
Теперь, очевидно, с этим можно справиться правильно. Например, команда ls
может сделать это для файлов namned ‘foo’
‘bar one’
и ‘bar two’
(хотя у него есть проблемы с некоторыми способами выражения имен файлов, когда вы используете (действительную) комбинацию как "
, '
и различные экраны). Тем не менее, я не мог понять, как ls
делает это, читая код завершения bash.
Итак, кто-нибудь знает, как правильно справиться с этим? Фактические входные котировки не обязательно сохраняются; Я был бы доволен решением, которое, например, меняет ‘words "b<tab>’
, ‘words 'b<tab>’
и ‘words b<tab>’
на ‘words bar\ ’
(хотя я бы предпочел лишить кавычек, как в этом примере, вместо их добавления).