Jak edytować uzupełnianie poleceń dla ssh na zsh?

11

Chciałbym skonfigurować uzupełnianie poleceń na zsh, aby wyświetlały nazwy hostów po wpisaniu

ssh [TAB]

usunięcie nazw z mojego pliku .ssh / config (najlepiej z znanych hostów i / etc / hosts i gdziekolwiek to ma sens) i przedstawienie jednej pojedynczej listy.

Obecnie robi to częściowo, ale

  1. w ogóle nie używa .ssh / config
  2. wymaga najpierw nazwy użytkownika, mimo że użycie .ssh / config sprawia, że ​​wpisywanie nazw użytkowników jest niepotrzebne
  3. prezentuje wiele list (prawdopodobnie jedną ze znanych hostów i drugą z / etc / hosts, ale tego nie zweryfikowałem)

Dlatego chcę wpisać znane nazwy użytkowników, a także znane nazwy hostów na liście (najlepiej pojedynczej) po wpisaniu ssh [TAB]

(Przychodzę tu przed Google, ponieważ 1) spowoduje zapisanie odpowiedzi tutaj i 2) prawdopodobnie jest bardziej wydajna. Jeśli nikt inny nie odpowie, odszukam odpowiedź.)

ikonoklasta
źródło
Myślę, że byłoby to pytanie dla superużytkownika
Etienne Perot
Właściwie, patrząc na to teraz, powinienem był to zadać na unix.stackexchange.com. (Ale nie pamiętam, czy to było około 2 lata temu, kiedy o to poprosiłem.) Czy ktoś chce go migrować?
iconoclast

Odpowiedzi:

16

Oto odpowiednia część z mojego .zshrc. Nie zmieniło się od 2002 roku, więc mogę dziś napisać inaczej, ale nadal działa, aby uzupełnić nazwy hostów od ~/.ssh/configi ~/.ssh/known_hosts(jeśli HashKnownHostsjest wyłączone - wtedy nie istniało).

h=()
if [[ -r ~/.ssh/config ]]; then
  h=($h ${${${(@M)${(f)"$(cat ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*})
fi
if [[ -r ~/.ssh/known_hosts ]]; then
  h=($h ${${${(f)"$(cat ~/.ssh/known_hosts{,2} || true)"}%%\ *}%%,*}) 2>/dev/null
fi
if [[ $#h -gt 0 ]]; then
  zstyle ':completion:*:ssh:*' hosts $h
  zstyle ':completion:*:slogin:*' hosts $h
fi
Gilles „SO- przestań być zły”
źródło
Okej, w końcu zorientowałem się, dlaczego to nie działa. Problem nie dotyczył kodu, który podałeś: działa dobrze, gdy drugi problem zostanie rozwiązany.
iconoclast
1

Funkcja zapewniająca sshzakończenie znajduje się w /usr/share/zsh/functions/Completion/Unix/_sshmoim systemie.

Zobacz także man zshcompsysdokumentację (szczególnie wyszukaj „host”, który pojawia się w wielu miejscach i „ssh”, który pojawia się w kilku miejscach).

Możliwe, że dodanie zstylepolecenia ~/.zshrcspowoduje zrobienie tego, czego szukasz, bez konieczności modyfikowania funkcji uzupełniania.

Wstrzymano do odwołania.
źródło
Lub w /usr/share/zsh/4.3.9/functions/_sshMac OS X (dostosuj wersję)
Studer
Pobieram ten plik, piszę ssh <TAB> i otrzymuję uzupełnienie nazwy pliku. Co z tym?
iconoclast
1

Robię to za pomocą listy wszystkich hostów w danej domenie za pomocą dig. Możesz zastąpić tę funkcję dowolnym systemem wyszukiwania, w tym plikiem hosta lub listą statyczną:

function complete_host_from_zone () {
    reply=(`dig axfr ouraynet.com @ns1.ouraynet.com | grep -e '^[a-z]' | cut -d\. -f1`)
}
compctl -x 'p[1]' -K complete_host_from_zone -- ssh

Uwaga: powyższy kod może nie całkowicie zastąpić całego systemu dla komendy ssh w konfiguracji. Jeśli masz z tym problemy, spróbuj zmienić komendę „ssh” na inną losową komendę, taką jak „mycompletetest” i sprawdź, czy zakończenie to działa.

Pamiętaj też, że powoduje to przeniesienie strefy dns przy każdym zakończeniu! Jeśli używasz tego często lub w dość statycznej domenie, sensowne byłoby wykonanie wyszukiwania i zapisanie wyniku, a następnie w funkcji wyszukiwania wystarczy ustawić odpowiedź = zone_result.

Caleb
źródło
Nie mogę tego w ogóle uruchomić. Oczywiście muszę zmienić część odpowiedzi, ale czy możesz podać działający przykład z tekstem statycznym, więc wiem, w jakim formacie powinien on być? (Próbowałem tego, co zrozumiałem na stronie podręcznika, i poprawiłem -k na -K, i nadal nie działało.)
iconoclast
Format odpowiedzi jest dość prosty, to po prostu kropla tekstu, jedna możliwa odpowiedź na wiersz. Sprawa dns jest prawdopodobnie trudną częścią. Twój serwer DNS musi obsługiwać transfer strefy, aby to działało. Zazwyczaj oznacza to, że musisz rozmawiać z podstawowym serwerem DNS dla danej domeny, w ten sposób dig axfr mydomain.com @ns1.mydomain.com. Upewnij się, że możesz uruchomić to ręcznie, a częścią danych wyjściowych powinna być lista hostów zarejestrowanych w tej domenie i ich A lub dowolne rekordy. Właśnie o to prosiłem, a potem odciąłem tylko część nazwy hosta, a nie w pełni kwalifikowany rekord.
Caleb,
Pamiętaj, że przepisałem przykładowy kod w odpowiedzi, aby był w pełni działającym rozwiązaniem do wycinania i wklejania, w tym do nazwy domeny, dla której działa wyszukiwanie transferu strefy. Następnie możesz dostosować do zestawu. Przepraszam za oryginał, który skończył się dwiema literówkami, kiedy zgarnąłem około 20 dodatkowych warstw rzeczy, które były w moim pliku .zshrc, co nie ma związku z tym przykładem.
Caleb,
Polecenie dig w backticksach działa teraz (dziękuję za edycję!), Ale nie wyświetla żadnego z wyników tego polecenia, gdy wpisuję ssh <TAB>. Czy jest coś jeszcze poza tym, co należy włączyć, zanim zadziała?
iconoclast
0

Lubię przechowywać known_hostsplik z hashowaniem i wolę się nie HashKnownHostswyłączać. Przekonałem się, że zasianie tego, co @Gilles ma już w mojej historii, jest całkiem skuteczne dla moich potrzeb.

h=($(echo $(history | awk '{print $4 " " $5 "\n"}' | grep 'ssh ' | awk '{print $2}' | sort -u)))
if [[ -r ~/.ssh/config ]]; then
  h=($h ${${${(@M)${(f)"$(cat ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*})
fi
if [[ -r ~/.ssh/known_hosts ]]; then
   h=($h ${${${(f)"$(cat ~/.ssh/known_hosts{,2} || true)"}%%\ *}%%,*}) 2>/dev/null
fi
if [[ $#h -gt 0 ]]; then
  zstyle ':completion:*:ssh:*' hosts $h
  zstyle ':completion:*:slogin:*' hosts $h
fi

Ponadto, FWIW, to właśnie użyłem do Bash:

# SSH Autocompletion
complete -W "
  $(echo $(grep '^\s*ssh ' ~/.bash_history | sort -u | sed 's/^ssh //' | awk '{print $1}'))
  $(echo $(history | awk '{print $2 " " $3}' | grep 'ssh ' | awk '{print $2}' | sort -u))
  $(sed 's/#.*//;' ~/.ssh/config | awk ' /^Host (.+)$/ {$1 = "";print tolower($0)}')
" ssh
Karl Wilbur
źródło