summaryrefslogtreecommitdiff
path: root/template
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2016-10-16 18:34:00 +0200
committeremkael <emkael@tlen.pl>2016-10-16 18:34:00 +0200
commite2a0a09f8ea60d343c304c31f5ac0e7b64dfacea (patch)
tree76624869f4502abcc4aea15354d7be59e8cdb91d /template
parentd91bd88618bb1ec361409a081be8fe18cbc20b18 (diff)
* bash completion articles
Diffstat (limited to 'template')
-rw-r--r--template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl98
-rw-r--r--template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl318
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>