#autocomplete #zsh #glob
#автозаполнение #zsh #глобус
Вопрос:
Я пытаюсь создать свой первый сценарий завершения zsh, в данном случае для команды netcfg.
Как бы неубедительно это ни звучало, я застрял на первом препятствии, отказ от ответственности, я знаю, как сделать это грубо, однако я ищу «СПОСОБ ZSH» для этого.
Мне нужно перечислить файлы в /etc / networking, но только файлы, а не компонент каталога, поэтому я делаю следующее.
echo $(ls /etc/network.d/*(.))
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
Чего я хотел, так это:
ethernet-dhcp wireless-wpa-config
Поэтому я пытаюсь (извините за мою наивность) :
echo ${(s/*/)$(ls /etc/network.d/*(.))}
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
Кажется, это не работает, я уверен, что должен быть какой-то умный способ сделать это, разбив на массив и получив последнюю часть, но, как я уже сказал, я полный новичок в этом.
С благодарностью принимаю любые советы.
Ответ №1:
Общее примечание: Нет необходимости использовать ls для генерации имен файлов. С таким же успехом вы могли бы использовать echo some*glob
. Но если вы хотите защитить возможные встроенные символы новой строки, даже это плохая идея. В первом примере, приведенном ниже, глобусы помещаются непосредственно в массив для защиты встроенных новых строк. Второй использует printf для генерации данных с завершением NUL, чтобы выполнить то же самое без использования переменной.
Это легко сделать, если вы готовы использовать переменную:
typeset -a entries
entries=(/etc/network.d/*(.)) # generate the list
echo ${entries#/etc/network.d/} # strip the prefix from each one
Вы также можете сделать это без переменной, но дополнительные материалы для изоляции отдельных записей немного уродливы:
# From the inside, to the outside:
# * glob the entries
# * NUL terminate them into a single string
# * split at NUL
# * strip the prefix from each one
echo ${${(0)"$(printf '%s' /etc/network.d/*(.))"}#/etc/network.d/}
Или, если вы все равно собираетесь использовать подоболочку (т. Е. Замену команды в предыдущем примере), просто вставьте компакт-диск в каталог, чтобы он не был частью расширения glob (плюс, вам не нужно повторять имя каталога):
echo ${(0)"$(cd /etc/network.d amp;amp; printf '%s' *(.))"}
Комментарии:
1. Жаль, что у меня есть только 1, чтобы указать. Три хороших варианта, все лучше, чем у меня. 🙂
Ответ №2:
Ответ Криса Джонсена полон полезной информации о zsh, однако в нем не упоминается гораздо более простое решение, которое работает в данном конкретном случае:
echo /etc/network.d/*(:t)
При этом используется t
модификатор истории в качестве квалификатора глобуса.
Комментарии:
1. Хорошее решение, но оно неправильно работает с пробелами в именах файлов.
2. @AntonK Часть с глобализацией работает должным образом с произвольными именами файлов. Единственная часть, которая имеет проблему, это
echo
. В реальном примере вы бы не использовалиecho
, вы бы передали список любой команде, которую хотите обработать файлы.
Ответ №3:
Спасибо за ваши предложения, ребята, после еще большего прочтения ZSH и возвращения к проблеме пару дней спустя, я думаю, что у меня есть очень краткое решение, которым я хотел бы поделиться в ваших интересах.
echo ${$(print /etc/network.d/*(.)):t}
Комментарии:
1. Использование подстановки процесса — плохая идея: это искажает имена файлов, содержащие пробелы, это более сложно и работает медленнее. Почему бы нет
echo /etc/network.d/*(.:t)
(или любой другой реальной команды, которую вы хотите заменитьecho
), которая была бы проще, надежнее и эффективнее?
Ответ №4:
Я привык видеть, как basename(1)
удаляются компоненты каталога; кроме того, вы можете использовать echo /etc/network/*
для получения списка файлов без запуска внешней ls
программы. (Запуск внешних программ может замедлить завершение больше, чем хотелось бы; я не нашел встроенного zsh для basename, но это не значит, что его нет.)
Вот кое-что, что, я надеюсь, поможет:
haig% for f in /etc/network/* ; do basename $f ; done if-down.d if-post-down.d if-pre-up.d if-up.d interfaces
Комментарии:
1.
${param#pattern}
Расширение параметра — это способ удаления префиксов.${param%pattern}
для удаления суффиксов.