Как работать с именами файлов, содержащими одну цитату внутри функции завершения zsh?

Я использую оболочку zsh и имею следующий код внутри моего .zshrc :

 fpath=(~/.zsh/completion $fpath) autoload -Uz _vc autoload -Uz compinit compinit 

Первая строка добавляет путь ~/.zsh/completion к массиву, хранящемуся внутри переменной fpath среды.

Вторая строка загружает функцию завершения, называемую _vc , для пользовательской функции оболочки, называемой vc . Цель vc – просто отредактировать файл внутри определенной папки ( ~/.cheat ). _vc определяется в файле ~/.zsh/completion/_vc .

Последние 2 строки включают систему завершения.

Вот код для моей функции завершения _vc :

 #compdef vc declare -a cheatsheets cheatsheets="$(ls ~/.cheat)" _arguments "1:cheatsheets:(${cheatsheets})" && return 0 

Я скопировал его с этого адреса и адаптировал его для моих нужд.

Пока каталог ~/.cheat не имеет файла, имя которого содержит одну цитату, завершение работы. Но если есть такой, как foo'bar , завершение завершается с этим сообщением об ошибке:

 (eval):56: unmatched ' (eval):56: unmatched ' (eval):56: unmatched ' (eval):56: unmatched ' 

Я нашел решение, заменив двойные кавычки в строке cheatsheets="$(ls ~/.cheat)" , с одиночными кавычками cheatsheets='$(ls ~/.cheat)' .

Теперь, когда я нажимаю Tab после моей команды vc , zsh предлагает файлы внутри ~/.cheat , включая foo\'bar (zsh, похоже, автоматически ускользает от одной кавычки).

Однако я не понимаю, как и почему это работает. С одинарными кавычками переменные cheatsheets могут содержать литеральную строку. Таким образом, подстановка $(...) не должна расширяться. Например, если я выполняю следующие команды:

 myvar='$(ls)' echo $myvar → outputs `$(ls)` literally 

Итак, почему '$(ls ~/.cheat)' расширен внутри _arguments "1:cheatsheets:(${cheatsheets})" && return 0 ? И почему он автоматически избегает одиночной цитаты внутри foo'bar ?

  • Список каталогов с точечными каталогами, затем точечными файлами
  • Выполнить команду в режиме zsh vim
  • Подсказка: замените пользовательский путь коротким словом, например ~ для дома
  • сценарий к cd во многие каталоги и выполнить команду
  • Что такое расщепление слов? Почему это важно в программировании оболочки?
  • Есть ли хороший способ установить локальные переменные среды каталога / проекта?
  • При использовании zsh tab-completion игнорируйте CDPATH, если локальный файл или каталог совпадают
  • Настроить tmux для использования zsh
  • One Solution collect form web for “Как работать с именами файлов, содержащими одну цитату внутри функции завершения zsh?”

    Если мы настаиваем на том, чтобы делать вещи The Wrong Way ™

     #compdef vc declare -a cheatsheets cheatsheets=(${(f)"$(ls ~/.cheat/)"}) _arguments '1:cheatsheets:(${cheatsheets})' && return 0 

    Тьфу! Это, конечно, сломается, если имя файла содержит новую строку, поскольку (f) разделяет их. Разбор ls – это любая плохая идея ; ZSH может собирать файлы непосредственно в массив:

     % mkdir ~/.lojban % touch ~/.lojban/{go\'i,na\ go\'i} % words=(~/.lojban/*) % print -l ${words:t} go'i na go'i % words=(~/.lojban/*(On)) % print -l ${words:t} na go'i go'i % 

    Но нам, вероятно, не нужен локальный массив; _files могут завершаться по глобусу:

     #compdef vc _arguments '1:cheatsheets:_files -g "~/.cheat/*"' && return 0 

    Это возвращает полностью определенные пути к файлу; если из каталога поиска требуется только голые имена файлов, мы можем вместо этого использовать:

     #compdef vc _arguments '1:cheatsheets:_files -W ~/.cheat' && return 0 
    Linux и Unix - лучшая ОС в мире.