ocehb: (Default)
[personal profile] ocehb
Перечитал zshexpn, приемы для работы с файлами.

В zsh можно сконфигурировать стиль для дополнений ssh, который по tab генерирует дополнения для, например, имени хоста. Логично брать их из ~/.ssh/config и ~/.ssh/known_hosts.

Форматы пересказывать не буду, их можно посмотрать по манам.
1. Разбор ~/.ssh/config, будем брать имена из строки Host name:
${(s. .)${${"${(@M)${(@f)"$(< ~/.ssh/config)"}:#Host[[:space:]][[:space:][:alnum:]-]##}"}#* }}

Легенда:

  • $(< ~/.ssh/config) читаем файл, результат — массив строк, разбитых по пробелам

  • "$(< ~/.ssh/config)", результат — файл, как он есть, без разбивки

  • ${(@f)"$(< ~/.ssh/config)} — разбиваем контент по строкам, получаем массив строк

  • ${(@M)${(f)"$(< ~/.ssh/config)"}:#Host[[:space:]][[:space:][:alnum:]-]#} — удаляем все, что не попадает под выражение Host name1( name2 ...):

    • В zsh можно использовать классы символов, как [:space:] класс пробелов и [:alnum:] класс алфавитно-цифровых символов. Символ # после класса обозначает повторение, для pcre это совпадает с Host\s+[\w\s]+

    • :# удалят из массива совпадающие с паттерном элементы, флаг M меняет действие на противоположное, удаляет не совпадающие элементы

    • Флаг @ показывает, что имеем дело с массивом.

    Результат:

    
    # print -l ${"${(M@)${(f)"$(< ~/.ssh/config)"}:#Host[[:space:]][[:alnum:][:space:]-]#}"}     
    Host roof
    Host arto home
    Host book
    Host sut
    Host ftp2
    ...
    


  • ${${"${(M@)${(@f)"$(< ~/.ssh/config)"}:#Host[[:space:]][[:alnum:][:space:]-]#}"}##* } — удаляет в каждом элементе массива подстроку сначала и до последнего пробела, оставляя имя хоста:

    # print -l ${${"${(M@)${(@f)"$(< ~/.ssh/config)"}:#Host[[:space:]][[:alnum:][:space:]-]#}"}##* }
    roof
    arto home
    book
    sut
    ftp2
    ...
    


  • (s. .) — делит каждую строку в массиве по пробелу, в результате получим чистый список всех хостов.



Для perl это будет выглядеть так: perl -lne 'm#Host\s+([\w\s]+)# && print $1' ~/.ssh/config, но порождается один дополнительный процесс.

2. Разбор ~/.ssh/known_hosts, хотим брать нормальные имена хостов, ip-адреса и адреса с портом ([host]:port) брать не будем:

# print -l ${${${"${(f)"$(< ~/.ssh/known_hosts)"}"%%[ ,]*}:#\[*\]:*}:#[0-9]#.[0-9]#.[0-9]#.[0-9]#} 
roof.***.ru
book.***.ru
cube.***.ru
ftp2.***.ru
...


Легенда:

  • $(< ~/.ssh/known_hosts) — читаем весь файл, с разбивкой по пробелам

  • "$(< ~/.ssh/known_hosts)" — весь файл без разбивок

  • ${(f)"$(< ~/.ssh/known_hosts)"} — разбиваем контент по строчкам

  • "${(f)"$(< ~/.ssh/known_hosts)"}" — экранируем каждый элемент массива (там могут попадаться спецсимволы, например [ и ]), результат:

    # print -l "${(f)"$(< ~/.ssh/known_hosts)"}"
    roof.***.ru,195.***.130 ssh-dss AAAAB3NzaC1kc3MAAAC...
    book.***.ru,195.***.246 ssh-rsa AAAAB3NzaC1yc2EAAAA...
    ...


  • ${"${(f)"$(< ~/.ssh/known_hosts)"}"%%[ ,]*} — удаляем теги и ключи, всё после пробела или запятой (%%[ ,]*)

  • ${${"${(f)"$(< ~/.ssh/known_hosts)"}"%%[ ,]*}:#\[*\]:*} — удаляем (#:) все элементы массива, совпадающие с паттерном (\[*\]:*, например [www.abc.ru]:22222)

  • ${${${"${(f)"$(< ~/.ssh/known_hosts)"}"%%[ ,]*}:#\[*\]:*}:#[0-9]#.[0-9]#.[0-9]#.[0-9]#} — удляем элементы массива (#:) совпадающие с ip-адресом ([0-9]#.[0-9]#.[0-9]#.[0-9]#)



Теперь можно проверить:

# zstyle ':completion:*:(ssh|scp|sftp):*' hosts ${(o)${${"${(f)"$(< ~/.ssh/known_hosts)"}"%%[ ,]*}:#\[*\]:*}:#[0-9]#.[0-9]#.[0-9]#.[0-9]#}
# ssh <TAB>
roof.***.ru    book.***.ru    cube.***.ru    ftp2.***.ru
...


This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

Profile

ocehb: (Default)
ocehb

January 2021

S M T W T F S
     12
345 6789
10111213141516
17181920212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 10th, 2026 12:00 pm
Powered by Dreamwidth Studios