Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

Zsh

Współczesna powłoka systemowa to dużo więcej niż okienko do wpisywania literek. Niektórzy z nas spędzają w niej wiele czasu i chcieliby wykonywać swoje działania możliwie najbardziej efektywnie. Zsh, to kolejna powłoka obok csh, tcsh, ksh, sh czy wreszcie domyślnego w większości dystrybucji Linuksa basha. Ceniony przez zaawansowanych użytkowników, pozwala wykonywać interaktywne zadania wygodniej niż alternatywy. Stopień pokrewieństwa zsh z innymi powłokami jest znaczny – w zasadzie ten shell dziedziczy najlepsze cechy konkurentów i dodaje własne. Nie będzie dużej przesady w stwierdzeniu, że zsh można używać jak basha i nawet wtedy będzie widać poprawę. Choć zsh pozwala pisać skrypty, a nawet oferuje w tym zakresie więcej niż bash, w praktyce lepiej pisać skrypty w bashu lub sh z uwagi na przenośność – zsh jest mistrzem pracy interaktywnej, powłoką z wyboru dla każdego kto spędza dużo czasu w terminalu.

Wbrew pozorom zsh nie jest żadną nowością – ma już ponad 20 lat. Ma świetną dokumentację (patrz ramka obok) i można znaleźć na jego temat w Internecie wiele artykułów i postów na blogach, ale w odróżnieniu do basha trudno do zsh znaleźć coś w księgarni, nawet w literaturze anglojęzycznej – jest w zasadzie tylko jedna książka: From Bash to Z Shell: Conquering the Command Line.

Konfiguracja

Niespodzianek nie ma:

~/.zshenv
przy każdym wejściu do shella
~/.zprofile
jak zshrc, ale wykonuje się przed nim
~/.zshrc
przy każdym wejściu do interaktywnego shella (aliasy, funkcje, opcje, skróty klawiaturowe itp.)
~/.zlogin
przy wejściu do login shella
~/.zlogout
przy wyjściu z login shella

Większość spośród mnóstwa opcji to flagi, do których ustawiania i anulowania służą polecenia setopt opcja i unsetopt opcja, a pełną listę pokazuje podręcznik systemowy zshoptions(1). Poniżej kilka co ciekawszych:

print_exit_value
wyświetla kod błędu polecenia, jeśli jest niezerowy
append_history
powłoka przy wyjściu dopisuje swoją historię do pliku historii zamiast nadpisywać plik

Zamiast find

Wzorzec ścieżki do pliku może zawierać sufiks ujęty w nawiasy okrągłe. Polecenie:

    ls -d *(x)

pokazuje pliki wykonywalne przez właściciela. Duże X oznacza „wykonywalne przez wszystkich”, inne flagi jak można się domyśleć to np. W (zapisywalne przez wszystkich) czy „r” (dające się odczytać przez właściciela). Ale możliwości jest więcej:

    ls -d *(^R)            # pliki nie dające się czytać przez wszystkich
    ls -d *(m0)            # pliki zmodyfikowane dzisiaj
    ls -d *(Lm+2)          # pliki o rozmiarze > 2 MB

Podwójna gwiazdka oznacza że będziemy przeszukiwać całe drzewo katalogów, a nie tylko bieżący katalog:

    ls **/Makefile
    chmod 700 **/(/) # tylko katalogi

Bieganie po katalogach

Zsh pozwala nadać etykietkę dowolnemu katalogowi w drzewie katalogów, aby później móc szybko skakać po drzewie:

    otocjon=$PWD
    ...
    cd ~otocjon

Skróty klawiaturowe

Dość typowa sytuacja: wpisujesz jakieś polecenie, ale żeby dokończyć edycję potrzebujesz dodatkowej informacji którą możesz otrzymać wykonując inne, pomocnicze polecenie powłoki. Naciśnij Alt-Q aby przenieść aktualnie edytowany wiersz do schowka, następnie wprowadź i wykonaj pomocnicze polecenie – natychmiast po jego wykonaniu w wierszu poleceń pojawi się pierwotne polecenie ze schowka, gotowe do edycji.

Alt-A wykonuje bieżące polecenie, po czym w wierszu poleceń pojawia się to samo polecenie gotowe do edycji, z kursorem w tym samym miejscu – przydatne gdy chcemy wielokrotnie wykonać to samo polecenie lub serię podobnych poleceń.

Ctrl-O wykonuje bieżące polecenie i wstawia do bufora następne polecenie z historii – wykonanie tego kilka razy pozwala wykonać ponownie kilka kolejnych poleceń z historii.

Jeśli podczas edycji polecenia zechcesz podejrzeć stronę manuala tego polecenia bez niszczenia zawartości wiersza wprowadzania, użyj Alt-H.

Jeśli nie chcesz rozwijać aktualnego wzorca pliku w poleceniu, ale chcesz zobaczyć co zostanie dopasowane, użyj Ctrl-Xg:

    % rm f*^Xg
    foo foo.c

Powiedzmy, że chcesz wyświetlić poleceniem echo następujący tekst:

    don't do that; type 'rm -rf \*', with a \ before the *.

Oczywiście trzeba go odpowiednio zacytować, ale żeby to zrobić wystarczy użyć kombinacji klawiszy Alt-‚, co spowoduje ujęcie całego aktualnie edytowanego wiersza w cudzysłowy i odpowiednie zacytowanie stosownych znaków łańcucha.

Możesz przypisywać skróty klawiszowe często wykonywanym poleceniom, np. wykonanie:

    % bindkey -s '^T' 'uptime
    > '

spowoduje, że każde naciśnięcie Ctrl-T wykona polecenie uptime.

Dopełnianie

Wszystkie współczesne powłoki starają się uzupełniać polecenia pod klawiszem TAB, ale zsh wydaje się być w tym zakresie niedościgniony oferując wręcz bizantyńskie możliwości – dopełnienie korzysta z analizy składniowej i kontekstowej już wprowadzonych znaków. Naciśnij klawisz TAB np. w takich kontekstach (podkreślenie symbolizuje pozycję kursora):

    kill _[TAB]
    ls -_[TAB]
    apt-get install ks_[TAB]

Polecenie:

    zstyle ':completion:*' menu select

spowoduje, że po dwukrotnym naciśnięciu TAB przy dopełnianiu będzie można wybrać jedno z dopełnień za pomocą klawiszy kursora.

Jeśli nie odpowiada nam sposób uzupełniania dla danego polecenia lub chcemy zdefiniować uzupełnianie dla własnego polecenia, sięgamy po polecenie compctl, np. poniższe polecenie powoduje, że podpowiadanym parametrem polecenia compress będzie dowolny plik inny niż *.Z, chyba że użyto opcji -d (rozpakuj), wówczas podpowiadany będzie plik pasujący do maski *.Z:

    compctl -g '^*.Z' -x 'r[-d,---]' -g '*.Z' -- compress

Zagadnieniem pokrewnym dla dopełniania jest poprawianie literówek. Zobaczmy jak to działa:

    % setopt correct
    % sl
    zsh: correct 'sl' to 'ls' [nyae]? y
    % setopt correctall
    % ls x.v11r4
    zsh: correct 'x.v11r4' to 'X.V11R4' [nyae]? n
    /usr/princton/src/x.v11r4 not found
    % ls /etc/paswd
    zsh: correct to '/etc/paswd' to '/etc/passwd' [nyae]? y
    /etc/passwd

Przekierowania

    echo Hello World >file1 >file2
    make > make.log | grep Error

Pierwsze polecenie przesyła standardowe wyjście do więcej niż jednego pliku, drugie polecenie przesyła wyjście zarówno do pliku jak i do strumienia. Ze standardowym wejściem też można robić ciekawe rzeczy:

    sort <file1 <file2 <file3
    cut -d: -f1 /etc/passwd | sort <newnames

Pierwsze polecenie pobiera wejście szeregowo z kilku plików, drugie polecenie pobiera na standardowym wejściu wynik cat, a następnie zawartość pliku newnames.

Jeśli chcesz wysłać wyjście zarówno do pliku, jak i na standardowe wyjście, możesz użyć np. takiego polecenia:

    echo Hello World >&1 >file1

W zsh, polecenie:

    % >file

jest równoważne

    % cat >file

natomiast

    % <file

oznacza to samo co

    % less file

Aliasy

Oprócz zwykłych aliasów, można też definiować aliasy globalne, które działają jak preprocesor w C. Można ich użyć jako skrótów często pisanych nazw użytkowników, hostów itp.

    alias -g me=paradox
    who | grep me
    alias -g M='| more'
    who M
    alias -g W=' | wc -l'

Na nazwy aliasów globalnych zaleca się wybierać napisy składające się z dużych liter – ewentualna pomyłka jest wówczas mało prawdopodobna.

Inne

Zsh jest powłoką rozszerzalną, można pisać własne moduły w C – pełna lista w podręczniku systemowym zshmodules(1). Np. aby dodać do shella trochę funkcji matematycznych:

    zmodload zsh/mathfunc
    echo $(( sin(1/4.0)**2 + cos(1/4.0)**2 - 1 ))

Nazwa polecenia poprzedzona znakiem równości rozwija się do pełnej ścieżki tego polecenia (ang. path expansion):

    echo =ls(:h)

Polecenie r powtarza polecenie z opcjonalnymi zmianami:

    % echo foo
    foo
    % r foo=bar
    echo bar
    bar

Polecenie:

    vared PATH

pozwala edytować wartość zmiennej.

Zwróć uwagę, że zsh pozwala przywołać wielowierszowe polecenie z historii, i edytować je jak w edytorze pełnotekstowym.

Modyfikatory

Z csh przejęto taką ciekawostkę:

    % echo $PWD
    /home/learning/pf/zsh/zsh2.00/src
    % echo $PWD:h
    /home/learning/pf/zsh/zsh2.00
    % echo $PWD:h:h
    /home/learning/pf/zsh
    % echo $PWD:t
    src
    % name=foo.c
    % echo $name:r
    foo
    % echo $name:e
    c
    % echo $name:u
    FOO.C
    % echo $name:s/foo/bar/
    bar.c

Przykładowy plik ~/.zshrc

    alias l='ls -dF'
    PS1=$'%{\e[1;31m%}%~> %{\e[0m%}'
    RPROMPT='%T'
    rm () { mv $* /tmp }
    HISTSIZE=200
    HISTFILE=~/.zsh_history
    SAVEHIST=200
    setopt share_history
    setopt inc_append_history

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>