diff options
author | emkael <emkael@tlen.pl> | 2016-10-16 18:34:00 +0200 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2016-10-16 18:34:00 +0200 |
commit | e2a0a09f8ea60d343c304c31f5ac0e7b64dfacea (patch) | |
tree | 76624869f4502abcc4aea15354d7be59e8cdb91d /template | |
parent | d91bd88618bb1ec361409a081be8fe18cbc20b18 (diff) |
* bash completion articles
Diffstat (limited to 'template')
-rw-r--r-- | template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl | 98 | ||||
-rw-r--r-- | template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl | 318 |
2 files changed, 416 insertions, 0 deletions
diff --git a/template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl b/template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl new file mode 100644 index 0000000..714fd77 --- /dev/null +++ b/template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl @@ -0,0 +1,98 @@ +<div class="page-header"> + <h1>Wprowadzenie do uzupełniania powłoki bash, część 1</h1> + <a href="2016/10/16/an-introduction-to-bash-completion-part-1/"> + <time class="text-muted" title="2016-10-16 11:05" datetime="2016-10-16T11:05">Sunday, October 16, 2016</time> + </a> +</div> + +<div class="panel panel-default"> + <div class="panel-body"> + <a href="https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1"> + Oryginalny artykuł autorstwa Steve'a Kempa (po angielsku). + </a><br /> + <a href="2016/10/16/an-introduction-to-bash-completion-part-2/"> + Druga część wprowadzenia. + </a> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-body"> + <p> + Jedną z najmilszych funkcjonalności nowoczesnych powłok jest wbudowana obsługa “uzupełniania”. Funkcje te umożliwiają łatwe uzupełnianie poleceń oraz ich argumentów. Czytajcie dalej, by poznać krótkie wprowadzenie do dodawania swojego własnego podpowiadania poleceń. + </p> + <p> + Większość powłok umożliwia podpowiadanie poleceń, zwykle związane z klawiszem <kbd>TAB</kbd>, które pozwala na uzupełnianie nazw poleceń dostępnych ze ścieżki wykonywania (<code>PATH</code>), nazw plików czy katalogów. Typowe użycie wygląda następująco: + <pre> +ls /bo<kbd>TAB</kbd></pre> + Po wciśnięciu klawisza <kbd>TAB</kbd>, argument <code>/bo</code> jest automatycznie zastępowany wartością <code>/boot</code>. + </p> + <p> + W ostatnich czasach niektóre powłoki zaczęły umożliwiać nawet więcej: uzupełniać <em>argumenty</em> poleceń. Dwie godne uwagi powłoki pozwalające na to, to zsh i bash. Jako że jestem użytkownikiem basha, omówię tylko nią. + </p> + <p> + <a href="http://packages.debian.org/bash">Debianowy pakiet <code>bash</code></a> dostarcza plik podpowiedzi <code>/etc/bash_completion</code>, który konfiguruje podstawową obslugę uzupełniania. + </p> + <p> + Jeśli go nie używacie, możecie załadować go poprzez wpisanie w Waszej powłoce <code>. /etc/bash_completion</code>, jak pokazano poniżej: + <pre>skx@lappy:~$ . /etc/bash_completion +skx@lappy:~$</pre> + </p> + <p> + Po wykonaniu tego polecenia, będziecie w stanie uzupełniać <kbd>TAB</kbd>em wiele popularnych argumentów programów, na przykład: + <pre>skx@lappy:~$ apt-get upd<kbd>TAB</kbd> +skx@lappy:~$ apt-get upg<kbd>TAB</kbd></pre> + </p> + <p> + Ale jak rozszerzyć tę funkcjonalność samemu? Cóż, dostarczone procedury uzupełniania używają kilku wewnętrznych poleceń basha, jak np. <code>complete</code>. Można ich użyć we własnych skryptach rozruchowych albo, łatwiej, tworząc niewielki plik i umieszczając go w katalogu <code>/etc/bash_completion.d/</code>. + </p> + <p> + W momencie, gdy plik <code>bash_completion</code> jest wykonywany (bądź ładowany), wszystko wewnątrz katalogu <code>/etc/bash_completion.d</code> jest również ładowane. To sprawia, że dodanie własnych rozszerzeń jest prostą sprawą. + </p> + <p> + Jednym ze słowników, z których bash potrafi podpowiadać wartości, jest zbiór nazw hostów, co może być przydatne wielu programom. + </p> + <p> + <a href="http://www.debian-administration.org/articles/135">Zarządzam zdalnie kilkoma komputerami, przy użyciu vnc</a> i zwykle robię to poprzez wywołanie polecenia <code>xvncviewer nazwa_hosta</code>. + </p> + <p> + Aby umożliwić bashowi podpowiadanie fragmentów nazw hostów, które wpisuję, zastosujemy komendę complete do poinformowania, że <code>xvncviewer</code> wymaga nazwy hosta: + <pre>skx@lappy:~$ complete -F _known_hosts xvncviewer</pre> + </p> + <p> + Po wykonaniu tej operacji mogę wcisnąć <kbd>TAB</kbd>, by uzupełnić nazwy hostów: + <pre>skx@lappy:~$ xvncviewer s<kbd>TAB</kbd> +savannah.gnu.org ssh.tardis.ed.ac.uk +scratchy steve.org.uk +security.debian.org security-master.debian.org +sun +skx@lappy:~$ xvncviewer sc<kbd>TAB</kbd></pre> + </p> + <p> + Powyższe właśnie uzupełniło dla mnie nazwę hosta <code>scratchy</code>. + </p> + <p> + Funkcja <code>_known_hosts</code> została zdefiniowana w pliku <code>/etc/bash_completion</code>. Skąd wiedziałem, że mogę jej użyć? Podając polecenie <code>complete -p</code>, by wyświetlić wszystkie skojarzone nazwy do użycia: + <pre>skx@lappy:~$ complete -p +.... +complete -F _known_hosts tracepath6 +complete -F _known_hosts host +...</pre> + </p> + <p> + Czego nauczyliśmy się dotychczas? + <ul> + <li>Istnieje coś takiego, jak uzupełnianie wiersza poleceń.</li> + <li>Uzupełnianie jest zaimplementowane w pliku <code>/etc/bash_completion</code></li> + <li>Nowe polecenia uzupełniania mogą zostać umieszczone w katalogu <code>/etc/bash_completion.d</code></li> + <li>Możemy wypisać wszystkie bieżące procedury uzupełniania poprzez <code>complete -p</code></li> + </ul> + </p> + <p> + W drugiej części zerkniemy na definiowanie własnych procedur obsługujących linię poleceń – podobnych do już istniejących. Będziemy mogli dodać uzupełnianie wiersza poleceń dla własnych programów, lub nieobsługiwanych jeszcze poleceń. + </p> + <p> + Do tego czasu, poeksperymentujcie trochę. + </p> + </div> +</div> diff --git a/template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl b/template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl new file mode 100644 index 0000000..b2a5e2e --- /dev/null +++ b/template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl @@ -0,0 +1,318 @@ +<div class="page-header"> + <h1>Wprowadzenie do uzupełniania powłoki bash, część 2</h1> + <a href="2016/10/16/an-introduction-to-bash-completion-part-2/"> + <time class="text-muted" title="2016-10-16 18:05" datetime="2016-10-16T18:05">Sunday, October 16, 2016</time> + </a> +</div> + +<div class="panel panel-default"> + <div class="panel-body"> + <a href="https://debian-administration.org/article/317/An_introduction_to_bash_completion_part_2"> + Oryginalny artykuł autorstwa Steve'a Kempa (po angielsku). + </a><br /> + <a href="2016/10/16/an-introduction-to-bash-completion-part-1/"> + Pierwsza część wprowadzenia. + </a> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-body"> + <p> + Dotychczas pokazaliśmy jak dodać podstawowe uzupełnianie do poleceń, używając gotowych mechanizmów dostępnych w pakiecie bash. W drugiej części pokażemy jak dodać zupełnie nowe, własne uzupełnianie poleceń. + </p> + <p> + W <a href="2016/10/16/an-introduction-to-bash-completion-part-1/">części pierwszej</a> zobaczyliśmy dodawanie uzupełniania nazw hostów do dowolnie wybranych poleceń używając: + <pre>complete -F _known_hosts xvncviewer</pre> + </p> + <p> + Metoda używa polecenia <code>complete</code> do powiadomienia basha, że funkcja <code>_known_hosts</code> powinna zostać użyta do obsługi uzupełniania argumentów dla <code>xvncviewer</code>. + </p> + <p> + Jeśli chcemy dodać własne uzupełnianie do polecenia, musimy napisać w jej miejsce swoją własną funkcję, i skojarzyć <em>ją</em> z poleceniem. + </p> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3>Prosty przykład</h3> + </div> + <div class="panel-body"> + <p> + Jako podstawowy przykład, spróbujemy dodać proste uzupełnianie do programu <code>foo</code>. To przykładowe polecenie przyjmuje trzy argumenty: + <ul> + <li> + <dt>--help</dt> + <dd> + Wyświetla opcje pomocy dla <code>foo</code>, i kończy wykonanie. + </dd> + </li> + <li> + <dt>--version</dt> + <dd> + Pokazuje wersję polecenia <code>foo</code>, i kończy wykonanie. + </dd> + </li> + <li> + <dt>--verbose</dt> + <dd> + Uruchamia <code>foo</code> w trybie szczegółowego wyjścia + </dd> + </li> + </ul> + </p> + <p> + Do obsługi tych argumentów utworzymy nowy plik <code>/etc/bash_completion.d/foo</code>. Plik ten będzie automatycznie dołączony (lub załadowany), gdy ładowany jest kod uzupełniania basha. + </p> + <p> + Wewnątrz tego pliku zapisz poniższą treść: + <pre>{literal} +_foo() +{ + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="--help --verbose --version" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi +} + +complete -F _foo foo{/literal}</pre> + </p> + <p> + Bo go przetestować, możesz teraz dołączyć plik: + <pre> +skx@lappy:~$ . /etc/bash_completion.d/foo +skx@lappy:~$ foo --<kbd>TAB</kbd> + --help --verbose --version</pre> + </p> + <p> + Eksperymentując, przekonasz się, że argumenty są poprawnie uzupełniane, zgodnie z oczekiwaniami. Wpisanie <code>foo --h<kbd>TAB</kbd></code> powoduje uzupełnienie argumentu <code>--help</code>. Wciśnięcie <kbd>TAB</kbd> kilka razy powoduje wyświetlenie listy wszystkich podpowiedzi. (W tym wypadku nie ma nawet znaczenia, że program o nazwie <code>foo</code> nie jest dostępny w Twoim systemie.) + </p> + <p> + Skoro dysponujemy działającym przykładem, powinniśmy spojrzeć, w <em>jaki</em> sposób działa! + </p> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3>Jak działa uzupełnianie</h3> + </div> + <div class="panel-body"> + <p> + Poprzedni przykład pokazywał prostą funkcję basha, która była wywoływana do obsługi uzupełniania dla polecenia. + </p> + <p> + Funkcja na początku definiuje kilka zmiennych, <code>cur</code> – bieżące wpisywane słowo, <code>prev</code> – poprzednie wpisane słowo, oraz <code>opts</code> – nasza lista opcji do uzupełnienia. + </p> + <p> + Uzupełnianie opcji jest następnie obsługiwane poprzez użycie komendy <code>compgen</code> w następującym wywołaniu: + <pre>{literal} +COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ){/literal}</pre> + </p> + <p> + Sprawia to ustawienie wartości zmiennej <code>$COMPREPLY</code> na wyjście polecenia: + <pre>{literal} +compgen -W "${opts}" -- ${cur}{/literal}</pre> + </p> + <p> + Gdyby zastąpić te zmienne ich wartościami, przekonamy się, jak ono działa: + <pre>compgen -W "--help --verbose --version" -- "userinput"</pre> + </p> + <p> + Polecenie usiłuje zwrócić dopasowanie bieżącego słowa <code>{literal}${cur}{/literal}</code> do listy <code>--help --verbose --version</code>. Po wywołaniu go w powłoce, będziesz w stanie przekonać się, jak to działa: + <pre>skx@lappy:~$ compgen -W "--help --verbose --version" -- -- +--help +--verbose +--version +skx@lappy:~$ compgen -W "--help --verbose --version" -- --h +--help</pre> + </p> + <p> + Na początku widać, co się stanie, gdy użytkownik wpisze jedynie <code>--</code> - wszystkie trzy opcje pasują, więc są zwracane. Przy drugiej próbie, użytkownik wprowadza <code>--h</code>. I to wystarcza do jednoznacznego dopasowania <code>--help</code>, więc to jest zwracane. + </p> + <p> + W naszej funkcji, po prostu ustawiamy nasz wynik jako <code>COMPREPLY</code>, i kończymy wywołanie. To pozwala bashowi zastąpić bieżące słowo wyjściem. <code>COMPREPLY</code> jest specjalną zmienną, która ma konkretne znaczenie wewnątrz basha. W procedurach uzupełniania używana jest do oznaczania wyniku próby uzupełniania. + </p> + <p> + Z <a href="http://www.gnu.org/software/bash/manual/bash.html">dokumentacji basha (ang.)</a> możemy dowiedzieć się opisu <code>COMPREPLY</code>: + <blockquote> + <dt>COMPREPLY</dt> + <dd>Zmienna tablicowa, z której Bash czyta możliwe uzupełnienia wygenerowane przez funkcję powłoki wywoływaną przez podsystem programowalnego uzupełniania</dd> + <p> + Możemy również dowiedzieć się, w jaki sposób znaleźliśmy bieżące słowo, używając tablicy <code>COMP_WORDS</code> do odszukania zarówno bieżącego, jak i poprzedniego słowa: + <dt>COMP_WORDS</dt> + <dd>Zmienna tablicowa składająca się z pojedynczych słów w bieżącym wierszu poleceń. Zmienna ta jest dostępna tylko w funkcjach powłoki wywoływanych przez podsystem programowalnego uzupełniania.</dd> + <dt>COMP_CWORD</dt> + <dd>Indeks tablicy <code>{literal}${COMP_WORDS}{/literal}</code> słowa zawierającego bieżącą pozycję kursora. Zmienna ta jest dostępna tylko w funkcjach powłoki wywoływanych przez podsystem programowalnego uzupełniania</dd> + </p> + </blockquote> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3>Złożony przykład</h3> + </div> + <div class="panel-body"> + <p> + Wiele poleceń jest bardziej skomplikowane do uzupełnienia, i posiada liczne opcje zależne od poprzednich. + </p> + <p> + Jako przykład posłuży dostarczane z Xen polecenie xm, posiadające podstawowe opcje: + <ul> + <li> + <dt>xm list</dt> + <dd>Wypisuje wszystkie uruchomione instancje Xen</dd> + </li> + <li> + <dt>xm create ConfigName</dt> + <dd>Tworzy nową instancję Xen używając pliku konfiguracyjnego z <code>/etc/xen</code> o nazwie <code>ConfigName</code>.</dd> + </li> + <li> + <dt>xm console Name</dt> + <dd>Łączy z konsolą uruchomionej maszyny o nazwie <code>Name</code>.</dd> + </li> + </ul> + </p> + <p> + Przeważnie polecenie wywołuje się jako <code>xm operation args</code>, gdzie <code>args</code> różni się w zależności od wybranego argumentu <code>operation</code>. + </p> + <p> + Konfiguracja prostego uzupełniania pierwszego słowa – operacji – może zostać obsłużone w ten sam sposób, co w naszym poprzednim przykładzie, przy czym operacje nie zaczynają się od prefiksu <code>--</code>. Uzupełnienie argumentów operacji natomiast wymaga specjalnej obsługi. + </p> + <p> + Jak pamiętacie, mamy dostęp do poprzedniego słowa wiersza poleceń, i używając go, możemy rozróżnić akcje dla poszczególnych operacji. + </p> + <p> + Przykładowy kod wygląda następująco: + <pre>{literal} +_xm() +{ + local cur prev opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + # + # The basic options we'll complete. + # + opts="console create list" + + + # + # Complete the arguments to some of the basic commands. + # + case "${prev}" in + console) + local running=$(for x in `xm list --long | grep \(name | grep -v Domain-0 | awk '{ print $2 }' | tr -d \)`; do echo ${x} ; done ) + COMPREPLY=( $(compgen -W "${running}" -- ${cur}) ) + return 0 + ;; + create) + local names=$(for x in `ls -1 /etc/xen/*.cfg`; do echo ${x/\/etc\/xen\//} ; done ) + COMPREPLY=( $(compgen -W "${names}" -- ${cur}) ) + return 0 + ;; + *) + ;; + esac + + COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + return 0 +} + +complete -F _xm xm{/literal}</pre> + </p> + <p> + Skonfigurowaliśmy początkowe uzupełnianie operacji i dodaliśmy specjalną obsługę dwóch operacji: <code>create</code> i <code>console</code>. W obu przypadkach używamy compgen do uzupełnienia wejścia w zależności od tekstu podanego przez użytkownika, porównując je z dynamicznie generowaną listą. + </p> + <p> + Dla operacji <code>console</code> uzupełniamy na podstawie wyjścia poniższego polecenia: + <pre>{literal}xm list --long | grep \(name | grep -v Domain-0 | awk '{ print $2 }' | tr -d \){/literal}</pre> + </p> + <p> + Zwraca ono listę uruchomionych systemów Xen. + </p> + <p> + Dla operacji tworzenia, uzupełniamy na podstawie wyjścia poniższego polecenia: + <pre>{literal}for x in `ls -1 /etc/xen/*.cfg`; do echo ${x/\/etc\/xen\//} ; done{/literal}</pre> + </p> + <p> + Przekształca ono listing katalogu <code>/etc/xen</code> w wyjście składające się z nazw plików zakończonych ciągiem <code>.cfg</code>. Na przykład: + <pre>{literal} +skx@lappy:~$ for x in `ls -1 /etc/xen/*.cfg`; do echo ${x/\/etc\/xen\//}; done +etch.cfg +root.cfg +sarge.cfg +steve.cfg +x.cfg +skx@lappy:~${/literal}</pre> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-heading"> + <h3>Inne uzupełniania</h3> + </div> + <div class="panel-body"> + <p> + Używając polecenia <code>compgen</code>, pokazaliśmy, jak dopasować wejście użytkownika do list konkretnych łańcuchów znaków, zarówno używając ustalonej listy możliwości, jak i wyjścia innych poleceń. + </p> + <p> + Możliwe jest również użycie nazw katalogów, nazw procesów oraz innych rzeczy. Pełen opis można zobaczyć w podręczniku basha, poprzez wywołanie polecenia <code>man bash</code>. + </p> + <p> + Końcowy przykład pokazuje, jak uzupełniać nazwy plików i hostów w odpowiedzi na dwie pierwsze opcje: + <pre>{literal} +# +# Completion for foo: +# +# foo file [filename] +# foo hostname [hostname] +# +_foo() +{ + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="file hostname" + + case "${prev}" in + file) + COMPREPLY=( $(compgen -f ${cur}) ) + return 0 + ;; + hostname) + COMPREPLY=( $(compgen -A hostname ${cur}) ) + return 0 + ;; + *) + ;; + esac + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) +} + +complete -F _foo foo{/literal}</pre> + </p> + </div> +</div> + +<div class="panel panel-default"> + <div class="panel-body"> + <p> + Używając tych przykładów, powinniście móc stworzyć własne funkcje obsługi uzupełniania. W 95% przypadków będziecie potrzebować uzupełniania spośród zbioru dostępnych opcji, w pozostałych przypadkach będziecie mieć do czynienia z dynamicznym generowaniem argumentów, jak pokazaliśmy na przykładzie <code>xm</code>. + </p> + <p> + Prawdopodobnie najlepszym podejściem jest rozbicie opcji na zbiór potoków wiersza poleceń i przetestowanie ich poza środowiskiem uzupełniania (po prostu, w powłoce), a następnie po prostu wklejenie gotowych poleceń do funkcji uzupełniania. + </p> + </div> +</div> |