From e2a0a09f8ea60d343c304c31f5ac0e7b64dfacea Mon Sep 17 00:00:00 2001 From: emkael Date: Sun, 16 Oct 2016 18:34:00 +0200 Subject: * bash completion articles --- .../an-introduction-to-bash-completion-part-1.tpl | 98 +++++++ .../an-introduction-to-bash-completion-part-2.tpl | 318 +++++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 template/content/2016/10/16/an-introduction-to-bash-completion-part-1.tpl create mode 100644 template/content/2016/10/16/an-introduction-to-bash-completion-part-2.tpl (limited to 'template') 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 @@ + + +
+ +
+ +
+
+

+ 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ń. +

+

+ Większość powłok umożliwia podpowiadanie poleceń, zwykle związane z klawiszem TAB, które pozwala na uzupełnianie nazw poleceń dostępnych ze ścieżki wykonywania (PATH), nazw plików czy katalogów. Typowe użycie wygląda następująco: +

+ls /boTAB
+ Po wciśnięciu klawisza TAB, argument /bo jest automatycznie zastępowany wartością /boot. +

+

+ W ostatnich czasach niektóre powłoki zaczęły umożliwiać nawet więcej: uzupełniać argumenty poleceń. Dwie godne uwagi powłoki pozwalające na to, to zsh i bash. Jako że jestem użytkownikiem basha, omówię tylko nią. +

+

+ Debianowy pakiet bash dostarcza plik podpowiedzi /etc/bash_completion, który konfiguruje podstawową obslugę uzupełniania. +

+

+ Jeśli go nie używacie, możecie załadować go poprzez wpisanie w Waszej powłoce . /etc/bash_completion, jak pokazano poniżej: +

skx@lappy:~$ . /etc/bash_completion
+skx@lappy:~$
+

+

+ Po wykonaniu tego polecenia, będziecie w stanie uzupełniać TABem wiele popularnych argumentów programów, na przykład: +

skx@lappy:~$ apt-get updTAB
+skx@lappy:~$ apt-get upgTAB
+

+

+ Ale jak rozszerzyć tę funkcjonalność samemu? Cóż, dostarczone procedury uzupełniania używają kilku wewnętrznych poleceń basha, jak np. complete. Można ich użyć we własnych skryptach rozruchowych albo, łatwiej, tworząc niewielki plik i umieszczając go w katalogu /etc/bash_completion.d/. +

+

+ W momencie, gdy plik bash_completion jest wykonywany (bądź ładowany), wszystko wewnątrz katalogu /etc/bash_completion.d jest również ładowane. To sprawia, że dodanie własnych rozszerzeń jest prostą sprawą. +

+

+ 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. +

+

+ Zarządzam zdalnie kilkoma komputerami, przy użyciu vnc i zwykle robię to poprzez wywołanie polecenia xvncviewer nazwa_hosta. +

+

+ Aby umożliwić bashowi podpowiadanie fragmentów nazw hostów, które wpisuję, zastosujemy komendę complete do poinformowania, że xvncviewer wymaga nazwy hosta: +

skx@lappy:~$ complete -F _known_hosts xvncviewer
+

+

+ Po wykonaniu tej operacji mogę wcisnąć TAB, by uzupełnić nazwy hostów: +

skx@lappy:~$ xvncviewer sTAB
+savannah.gnu.org            ssh.tardis.ed.ac.uk
+scratchy                    steve.org.uk
+security.debian.org         security-master.debian.org
+sun
+skx@lappy:~$ xvncviewer scTAB
+

+

+ Powyższe właśnie uzupełniło dla mnie nazwę hosta scratchy. +

+

+ Funkcja _known_hosts została zdefiniowana w pliku /etc/bash_completion. Skąd wiedziałem, że mogę jej użyć? Podając polecenie complete -p, by wyświetlić wszystkie skojarzone nazwy do użycia: +

skx@lappy:~$ complete -p
+....
+complete -F _known_hosts tracepath6
+complete -F _known_hosts host
+...
+

+

+ Czego nauczyliśmy się dotychczas? +

    +
  • Istnieje coś takiego, jak uzupełnianie wiersza poleceń.
  • +
  • Uzupełnianie jest zaimplementowane w pliku /etc/bash_completion
  • +
  • Nowe polecenia uzupełniania mogą zostać umieszczone w katalogu /etc/bash_completion.d
  • +
  • Możemy wypisać wszystkie bieżące procedury uzupełniania poprzez complete -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ń. +

+

+ Do tego czasu, poeksperymentujcie trochę. +

+
+
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 @@ + + +
+ +
+ +
+
+

+ 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ń. +

+

+ W części pierwszej zobaczyliśmy dodawanie uzupełniania nazw hostów do dowolnie wybranych poleceń używając: +

complete -F _known_hosts xvncviewer
+

+

+ Metoda używa polecenia complete do powiadomienia basha, że funkcja _known_hosts powinna zostać użyta do obsługi uzupełniania argumentów dla xvncviewer. +

+

+ Jeśli chcemy dodać własne uzupełnianie do polecenia, musimy napisać w jej miejsce swoją własną funkcję, i skojarzyć z poleceniem. +

+
+
+ +
+
+

Prosty przykład

+
+
+

+ Jako podstawowy przykład, spróbujemy dodać proste uzupełnianie do programu foo. To przykładowe polecenie przyjmuje trzy argumenty: +

    +
  • +
    --help
    +
    + Wyświetla opcje pomocy dla foo, i kończy wykonanie. +
    +
  • +
  • +
    --version
    +
    + Pokazuje wersję polecenia foo, i kończy wykonanie. +
    +
  • +
  • +
    --verbose
    +
    + Uruchamia foo w trybie szczegółowego wyjścia +
    +
  • +
+

+

+ Do obsługi tych argumentów utworzymy nowy plik /etc/bash_completion.d/foo. Plik ten będzie automatycznie dołączony (lub załadowany), gdy ładowany jest kod uzupełniania basha. +

+

+ Wewnątrz tego pliku zapisz poniższą treść: +

{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}
+

+

+ Bo go przetestować, możesz teraz dołączyć plik: +

+skx@lappy:~$ . /etc/bash_completion.d/foo
+skx@lappy:~$ foo --TAB
+    --help     --verbose  --version
+

+

+ Eksperymentując, przekonasz się, że argumenty są poprawnie uzupełniane, zgodnie z oczekiwaniami. Wpisanie foo --hTAB powoduje uzupełnienie argumentu --help. Wciśnięcie TAB kilka razy powoduje wyświetlenie listy wszystkich podpowiedzi. (W tym wypadku nie ma nawet znaczenia, że program o nazwie foo nie jest dostępny w Twoim systemie.) +

+

+ Skoro dysponujemy działającym przykładem, powinniśmy spojrzeć, w jaki sposób działa! +

+
+
+ +
+
+

Jak działa uzupełnianie

+
+
+

+ Poprzedni przykład pokazywał prostą funkcję basha, która była wywoływana do obsługi uzupełniania dla polecenia. +

+

+ Funkcja na początku definiuje kilka zmiennych, cur – bieżące wpisywane słowo, prev – poprzednie wpisane słowo, oraz opts – nasza lista opcji do uzupełnienia. +

+

+ Uzupełnianie opcji jest następnie obsługiwane poprzez użycie komendy compgen w następującym wywołaniu: +

{literal}
+COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ){/literal}
+

+

+ Sprawia to ustawienie wartości zmiennej $COMPREPLY na wyjście polecenia: +

{literal}
+compgen -W "${opts}" -- ${cur}{/literal}
+

+

+ Gdyby zastąpić te zmienne ich wartościami, przekonamy się, jak ono działa: +

compgen -W "--help --verbose --version" -- "userinput"
+

+

+ Polecenie usiłuje zwrócić dopasowanie bieżącego słowa {literal}${cur}{/literal} do listy --help --verbose --version. Po wywołaniu go w powłoce, będziesz w stanie przekonać się, jak to działa: +

skx@lappy:~$ compgen -W "--help --verbose --version" -- --
+--help
+--verbose
+--version
+skx@lappy:~$ compgen -W "--help --verbose --version" -- --h
+--help
+

+

+ Na początku widać, co się stanie, gdy użytkownik wpisze jedynie -- - wszystkie trzy opcje pasują, więc są zwracane. Przy drugiej próbie, użytkownik wprowadza --h. I to wystarcza do jednoznacznego dopasowania --help, więc to jest zwracane. +

+

+ W naszej funkcji, po prostu ustawiamy nasz wynik jako COMPREPLY, i kończymy wywołanie. To pozwala bashowi zastąpić bieżące słowo wyjściem. COMPREPLY 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. +

+

+ Z dokumentacji basha (ang.) możemy dowiedzieć się opisu COMPREPLY: +

+
COMPREPLY
+
Zmienna tablicowa, z której Bash czyta możliwe uzupełnienia wygenerowane przez funkcję powłoki wywoływaną przez podsystem programowalnego uzupełniania
+

+ Możemy również dowiedzieć się, w jaki sposób znaleźliśmy bieżące słowo, używając tablicy COMP_WORDS do odszukania zarówno bieżącego, jak i poprzedniego słowa: +

COMP_WORDS
+
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.
+
COMP_CWORD
+
Indeks tablicy {literal}${COMP_WORDS}{/literal} 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
+

+
+
+
+ +
+
+

Złożony przykład

+
+
+

+ Wiele poleceń jest bardziej skomplikowane do uzupełnienia, i posiada liczne opcje zależne od poprzednich. +

+

+ Jako przykład posłuży dostarczane z Xen polecenie xm, posiadające podstawowe opcje: +

    +
  • +
    xm list
    +
    Wypisuje wszystkie uruchomione instancje Xen
    +
  • +
  • +
    xm create ConfigName
    +
    Tworzy nową instancję Xen używając pliku konfiguracyjnego z /etc/xen o nazwie ConfigName.
    +
  • +
  • +
    xm console Name
    +
    Łączy z konsolą uruchomionej maszyny o nazwie Name.
    +
  • +
+

+

+ Przeważnie polecenie wywołuje się jako xm operation args, gdzie args różni się w zależności od wybranego argumentu operation. +

+

+ 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 --. Uzupełnienie argumentów operacji natomiast wymaga specjalnej obsługi. +

+

+ 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. +

+

+ Przykładowy kod wygląda następująco: +

{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}
+

+

+ Skonfigurowaliśmy początkowe uzupełnianie operacji i dodaliśmy specjalną obsługę dwóch operacji: create i console. 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ą. +

+

+ Dla operacji console uzupełniamy na podstawie wyjścia poniższego polecenia: +

{literal}xm list --long | grep \(name | grep -v Domain-0 | awk '{ print $2 }' | tr -d \){/literal}
+

+

+ Zwraca ono listę uruchomionych systemów Xen. +

+

+ Dla operacji tworzenia, uzupełniamy na podstawie wyjścia poniższego polecenia: +

{literal}for x in `ls -1 /etc/xen/*.cfg`; do echo ${x/\/etc\/xen\//} ; done{/literal}
+

+

+ Przekształca ono listing katalogu /etc/xen w wyjście składające się z nazw plików zakończonych ciągiem .cfg. Na przykład: +

{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}
+
+
+ +
+
+

Inne uzupełniania

+
+
+

+ Używając polecenia compgen, 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ń. +

+

+ 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 man bash. +

+

+ Końcowy przykład pokazuje, jak uzupełniać nazwy plików i hostów w odpowiedzi na dwie pierwsze opcje: +

{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}
+

+
+
+ +
+
+

+ 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 xm. +

+

+ 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. +

+
+
-- cgit v1.2.3