Od dosyć dawna Bash posiada wsparcie dla dopełniania nazw plików, jednak nie wszyscy zdają sobie sprawę, że dopełniać klawiszem TAB możemy praktycznie wszystko. Jest to mechanizm wysoce konfigurowalny i wiele dystrybucji posiada skrypt /etc/bash_completion który definiuje specjalne dopełnianie dla wielu popularnych poleceń - np dopełnianie opcji. Krótkie wprowadzenie można znaleźć tutaj - część pierwsza i druga.
W codziennej pracy administratora na pewno bardzo przydatną opcją jest dopełnianie nazw hostów. Doszukamy się nawet gotowego rozszerzenia dla ssh, scp i innych poleceń - zwykle wystarczy zainstalować tylko pakiet bash-completion. Rozszerzenie to potrafi nawet dopełniać w poleceniu scp nazwy plików i katalogów na zdalnym hoscie!
Cały mechanizm jest świetny, ale jak zapewne się już domyślacie jest jedna rzecz którą chce poprawić :) Dopełnianie nazw hostów bazuje na urządzeniach/komputerach do których już się zalogowaliśmy (poprzez ssh), lub takich które mamy zapisane w plikach hosts (np. /etc/hosts). Takie rozwiązanie nie sprawdza się w dużym środowisku, gdzie bardzo często logujemy się do hostów na których wcześniej nie byliśmy, dodatkowo dokładanych jest cały czas sporo maszyn a inne są usuwane.
Można ten problem rozwiązać instalując avahi... ale jest to trochę jak strzelanie z armaty do muchy, a dodatkowo musielibyśmy wprowadzić ten pakiet na większość maszyn.
Dla mnie idealnym rozwiązaniem jest dopełnianie nazw hostów bezpośrednio z serwera dns... jak? Po pierwsze musimy jakoś te nazwy wydobyć. Z pomocą przychodzi nam tutaj polecenie rndc dumpdb -zones które potrafi wylistować wszystkie strefy i zapisać je w pliku named_dump.db. Jest to plik tekstowy, który nadaje się idealnie do dalszej obróbki. Wykonujemy zatem polecenia dzięki którym wygenerujemy listę wszystkich hostów i stref zdefiniowanych w naszym lokalnym serwerze DNS:
# ssh root@zlomex.local "rndc dumpdb -zones; cat /var/cache/bind/named_dump.db" > named_dump.db
# sed -ne '/in-addr.arpa/d; s/^\([[:alnum:].-]\+\)\..*IN.*/\1/p' named_dump.db | sort | uniq > named_hosts.db
# rm named_dump.db
Mój serwer DNS to oczywiście zlomex.local :) Polecenia te najlepiej ustawić jako cyklicznie wykonywane zdanie cron, zwłaszcza jeżeli używamy do autentykacji kluczy ssh - nie musimy wtedy podawać hasła. Plik named_hosts.db zawiera teraz listę hostów:
local
localhost
test.local
wpad.local
zlomex.local
Następnie modyfikujemy standardowy skrypt dopełniający nazwy hostów, tak by uwzględnił zawartość pliku named_hosts.db. Edytujemy zatem /etc/bash_completion i szukamy funkcji _known_hosts_real() używanej do dopełniania nazw hostów. Przy końcu tej funkcji, ale przed wywołaniem __ltrim_colon_completions, dokładamy kilka linijek przeszukujących dodatkowo nasz plik named_hosts.db. Końcówka funkcji powinna zatem wyglądać podobnie jak poniżej:
named_hosts=$( grep "$cur" /etc/named_hosts.db )
if [ -n "$named_hosts" ]; then
COMPREPLY=( "${COMPREPLY[@]}" $named_hosts )
fi
__ltrim_colon_completions "$prefix$user$cur"
return 0
}
ps: Jeżeli nie mamy dostępu poprzez ssh do maszyny, możemy spróbować jeszcze polecenia listującego całą strefe, np dig @zlomex.local local axfr.
ps2: W ostateczności można również przelecieć poleceniem sed pliki konfiguracyjne binda ;)