Learn 10 Good Unix Usage Habits

Porady UNIX: Naucz się 10 pożytecznych zwyczajów w UNIXie

Odrzuć złe wzorce użytkowania UNIXa

Poziom: Średniozaawansowany

Michael Stutz (gro.lsd|ztuts#gro.lsd|ztuts), Autor, Konsultant

12 Grudzień 2006

Zapoznaj się z dziesięcioma zwyczajami które poprawią twoją efektywność w obsłudze linii poleceń w UNIXie(r). Ten artykuł poprowadzi Cię krok po kroku przez kilka sprawdzonych, lecz często lekceważonych, technik obsługi linii poleceń. Dowiedz się o powszechnych błędach i metodach przeciwdziałania im, abyś dokładnie wiedział dlaczego te nawyki w używaniu UNIXa są warte zainteresowania.

Wprowadzenie

Używając często systemu, masz tendencję do popadania w pewne wzorce zachowań. Czasami, nabywasz zwyczaj wykonywania pewnej czynności niekoniecznie w najlepszym z możliwych sposobów. Czasem wręcz nabywasz złych praktyk które skutkują nieładem i niezdarnością [kodu]. Jedną z najlepszych metod na poprawę tych błędów jest sumienne zapoznanie się z dobrymi wzorcami, które zniwelują złe nawyki. Ten artykuł podpowie Ci 10 sposobów obsługi linii poleceń w UNIXie, które warte są zainteresowania — dobre nawyki które pomogą Ci zniwelować Twoje słabostki w trakcie zwykłego użytkowania linii poleceń i sprawią że będziesz bardziej produktywny. Każdy sposób jest szczegółowo opisany, detale są umieszczone za listą dobrych nawyków.

Przyswój sobie dziesięć dobrych wzorców

Dziesięć dobrych wzorców to:

1. Twórz drzewa katalogów za jednym razem.
2. Zmieniaj ścieżkę; nie przenoś archiwów.
3. Łącz komendy z operatorami kontrolnymi.
4. Ostrożnie cytuj zmienne.
5. Używaj escape sequences do kontroli długich poleceń.
6. Łącz wiele poleceń w jedna listę.
7. Oprócz find używaj także xargs.
8. Wiedz kiedy użyć grep, a kiedy nie.
9. Porównuj nie tylko linie, ale i konkretne pola w danych wyjściowych.
10. Przestań nadużywać cat w przetwarzaniu potokowym/potokach.

Twórz drzewa katalogów za jednym razem.

Listing 1 pokazuje jeden z najbardziej powszechnych złych nawyków w UNIXie: tworzenie drzewa katalogów pojedynczo.

Listing 1. Przykład złego nawyku nr 1.: Tworzenie drzewa katalogów pojedynczo.

~ $ mkdir tmp
~ $ cd tmp
~/tmp $ mkdir a
~/tmp $ cd a
~/tmp/a $ mkdir b
~/tmp/a $ cd b
~/tmp/a/b/ $ mkdir c
~/tmp/a/b/ $ cd c
~/tmp/a/b/c $

Znacznie łatwiej jest użyć wraz z mkdir opcję -p i stworzyć katalogi nadrzędne i podrzędne za pomocą jednej komendy. Ale nawet administratorzy wiedzący o istnieniu tej opcji też się łapią na tym że tworzą katalogi jeden po drugim pracując w linii poleceń. Warto poświęcić trochę czasu aby nabrać dobrego zwyczaju:

Listing 2. Przykład dobrego zwyczaju nr 1.: Tworzenie drzewa katalogów jednym poleceniem

~ $ mkdir -p tmp/a/b/c

Możesz użyć tej opcji do tworzenia złożonych, kompleksowych drzew katalogów, nadających się do zastosowania w skryptach; nie tylko proste katalogi. Na przykład:

Listing 3. Kolejny przykład dobrego nawyku nr 1.: Tworzenie złożonego drzewa katalogowego jednym poleceniem

~ $ mkdir -p project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

W przeszłości, jedyną wymówką aby tworzyć katalogi pojedynczo było to że wcześniejsze wersje mkdir nie miały tej opcji, obecnie nie jest to prawdą w większości systemów. IBM, AIX(r), mkdir, GNU mkdir, i inne które odpowiadają "The Single UNIX Specification" posiadają tę opcję.

Dla kilku systemów które ciągle nie mają tej funkcjonalności, użyj mkdirhier script (dostępne w "Zasoby"), który jest nakładką na mkdir która wykonuje tę samą funkcje:

~ $ mkdirhier project/{lib/ext,bin,src,doc/{html,info,pdf},demo/stat/a}

Zmieniaj ścieżkę; nie przenoś archiwów.

Kolejnym złym nawykiem jest przenoszenie archiwów .tar do konkretnego katalogu ponieważ akurat tak się zdarza że właśnie w tym katalogu chcesz go rozpakować. Nie musisz tego robić. Możesz rozpakować dowolne archiwum .tar do dowolnego katalogu który sobie życzysz — właśnie opcja -C jest do tego. Używaj opcji -C rozpakowując archiwum .tar do wyznaczenia katalogu w którym chciałbyś go rozpakować:

Listing 4. Przykład dobrego nawyku nr 2.: Użycie opcji -C do rozpakowania archiwum .tar

~ $ tar xvf -C tmp/a/b/c newarc.tar.gz

Nawyk używania opcji -C jest przydatny do przenoszenia archiwów tam gdzie chcesz je rozpakować, zmieniając jedynie katalog docelowy i jedynie wtedy rozpakować zawartość pliku — szczególnie gdy archiwum znajduje się gdzieś indziej.

Łącz komendy z operatorami kontrolnymi.

Najprawdopodobniej wiesz już o tym że w większości powłok możesz łączyć komendy w jedną linię umieszczając pomiędzy nimi średnik (;). Średnik jest operatorem kontrolnym powłoki, i choć jest pożyteczny przy łączeniu razem wielu pojedynczych poleceń w jedną linię, nie zawsze działa. Dla przykładu, załóżmy że używasz średnika aby połączyć dwie komendy, gdzie prawidłowe wykonanie drugiego polecenia zależy w całości od zakończenia z sukcesem pierwszego zadania. Jeśli pierwsze zadanie nie zakończy się tak jak się można spodziewać, drugie zadanie się wykona — ale na darmo. Zamiast tego, użyj operatorów kontrolnych (część z nich opisana jest w tym artykule). Jeśli powłoka której używasz wspiera je, warto nabyć zwyczaju ich używania.

Wykonanie polecenia tylko jeśli inne polecenie się wykona / zostanie wysłany sygnał zero exit

Używaj operatora kontrolnego && aby połączyć ze sobą dwa polecenia w taki sposób, że drugie polecenie wykona się tylko wtedy gdy pierwsza komenda zwróci sygnał zero exit. Innymi słowy, jeśli pierwsze polecenie zakończy się sukcesem, to wtedy wykonane zostanie drugie polecenie. Jeśli zaś pierwsze polecenie się nie zakończy sukcesem, to drugie polecenie w ogóle się nie wykona. Na przykład:

Listing 5. Przykład dobrego nawyku nr.3.: Łączenie komend z operatorami kontrolnymi

~ $ cd tmp/a/b/c && tar xvf ~/archive.tar

W tym przykładzie zawartość archiwum jest wypakowywana do katalogu ~/tmp/a/b/c, chyba że katalog nie istnieje. Jeśli katalog nie istnieje, komenda tar nie wykona się i nic nie zostanie wypakowane.

Wykonanie komendy tylko jeśli inna, wcześniejsza komenda zwróci sygnał non-zero exit/nie wykona się

Podobnie jak wcześniej, operator kontrolny || oddziela dwie komendy, ale wykonuje drugie polecenie tylko wtedy gdy pierwsze polecenie zwróci sygnał non-zero exit. Innymi słowy, jeśli pierwsze polecenie zakończy się sukcesem, drugie polecenie się nie wykona. Natomiast jeśli pierwsze polecenie się nie wykona, wtedy zostanie wykonane polecenie drugie. Ten operator jest często używany do sprawdzania czy dany katalog istnieje, jeśli nie, zostaje on stworzony np.:

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c

Można także łączyć operatory kontrolne opisane w tym rozdziale. Każda z operacji uruchomi się tylko wtedy gdy poprzednia operacja zostanie wykonana:

Listing 7. Przykład łaczenia dobrych nawyków nr 3.: Łączenie poleceń z operatorami kontrolnymi

~ $ cd tmp/a/b/c || mkdir -p tmp/a/b/c && tar xvf -C tmp/a/b/c ~/archive.tar

Ostrożnie cytuj zmienne.

Zawsze bądź ostrożny z rozszerzeniami powłoki i nazwami zmiennych. Generalnie dobrym pomysłem jest umieszczać wywołania zmiennych w podwójnych cudzysłowach, chyba że masz dobry powód aby tego nie robić. Podobnie, jeśli bezpośrednio po nazwie zmiennej następuje tekst alfanumeryczny, bądź pewien że nazwa zmiennej jest zawarta w nawiasach sześciennych ({}) aby wyróżnić ją z otaczającego tekstu. W innym przypadku, powłoka zinterpretuje następujący po nazwie zmiennej tekst jako część nazwy zmiennej — i najprawdopodobniej zwróci wartość zero. Listing 8. przedstawia przykłady cytowania i niecytowania zmiennych i ich efekty.

Listing 8. Przykład dobrgo nawyku nr. 4.: Cytowanie (i nie cytowanie) zmiennych

~ $ ls tmp/
a b
~ $ VAR="tmp/*"
~ $ echo $VAR
tmp/a tmp/b
~ $ echo "$VAR"
tmp/*
~ $ echo $VARa

~ $ echo "$VARa"

~ $ echo "${VAR}a"
tmp/*a
~ $ echo ${VAR}a
tmp/a
~ $

Używaj escape sequences do kontroli długich poleceń.

Najprawdopodobniej widziałeś/-aś przykłady kodu w którym ukośnik (\) przeciąga całą linię komend do następnej linii, i wiesz, że większość powłok traktuje to co napisałeś w kolejnych liniach połączonych ukośnikiem jak jedną długą linię/listę poleceń. Jednak być może nie wykorzystujesz zalet tej funkcji tak często jak to możliwe. Ukośnik jest szczególnie poręczny jeśli twój terminal nie obsługuje prawidłowo zawijania wyrazów/linii lub jeżeli twoja linia poleceń jest mniejsza niż zwykle (np. kiedy znakiem zachęty jest dłuższa ścieżka). Ukośnik jest też używany aby sensownie, w trakcie wpisywania, łączyć polecenia w jedną, długą linię komend, tak jak w przykładzie:

Listing 9. Przykład dobrego nawyku nr 5.: Użycie ukośnika przy wpisywaniu długich poleceń
~ $ cd tmp/a/b/c || > mkdir -p tmp/a/b/c && > tar xvf -C tmp/a/b/c ~/archive.tar

Podobnie, podany poniżej przykład także zadziała:

Listing 10. Alternatywny przykład dobrego nawyku nr 5.: Użycie ukośnika przy wpisywaniu długich poleceń

~ $ cd tmp/a/b/c > || > mkdir -p tmp/a/b/c > && > tar xvf -C tmp/a/b/c ~/archive.tar

Jakkolwiek dzieląc jedną, długą linię komend na wiele linii, powłoka zawsze będzie traktować je jak jedną, ciągłą linię, ponieważ powłoka zawsze usuwa wszelkie ukośniki i spacje.

Zapamiętaj: W większości powłok, po naciśnięciu klawisza < Strzałka do góry >, wszystkie polecenia napisane w kilku liniach zostaną umieszczone w jednej linii.

Łącz wiele poleceń w jedna listę.

Większość powłok posiada rozwiązania pozwalające na grupowanie zestawów poleceń w listy, tak abyś mógł ich (całkowitą sumę wyników ???) wynik przenieść wzdłuż potoku poleceń lub przekierować wybrane lub wszystkie strumienie do tego samego miejsca. W zasadzie możesz to zrobić poprzez wykonanie listy poleceń w podpowłoce lub wykonując listę poleceń w aktualnej powłoce.

Wykonuj listy/ciągi poleceń w podpowłoce

Używaj nawiasów aby połączyć listę poleceń w jedną grupę/całość. Robiąc w ten sposób wykonujesz komendy w nowej podpowłoce, co pozwala Ci na przekierowanie lub też na zebranie wyników z grupy, tak jak w przykładzie:

Listing 11. Przykład dobrgo nawyku nr. 6.: Wykonywanie listy/ciągu poleceń w podpowłoce

~ $ ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && > VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) > | mailx admin -S "Archive contents"

W tym przykładzie zawartość archiwum jest wypakowywana do katalogu tmp/a/b/c/ a wynik ciągu poleceń, włączając w to listę wypakowanych plików jest wysyłany na skrzynkę mailową admin.

Używanie podpowłoki jest zalecane w przypadku kiedy są zmieniane zmienne środowiskowe w wykonywanej liście poleceń, a nie chcemy aby te zmienne wpływały na zmienne z powłoki.

Wykonuj listę poleceń w powłoce

Używaj nawiasów sześciennych ({}) aby zaznaczyć listę poleceń do wykonania w powłoce. Upewnij się że wstawiłeś spacje pomiędzy nawiasami a poleceniami, w innym przypadku powłoka mogłaby niepoprawnie zinterpretować nawiasy. Pozatym upewnij się że po ostatniej komendzie występuje średnik (;), tak jak w następującym przykładzie:

Listing 12. Przykład dobrgo nawyku nr. 6.: Wykonywanie listy/ciągu poleceń w powłoce

~ $ { cp ${VAR}a . && chown -R guest.guest a && > tar cvf newarchive.tar a; } | mailx admin -S "New archive"

Oprócz find używaj też xargs

Używaj narzędzia xargs jako filtru aby w pełni spożytkować wynik zastosowania komendy find. Ogólny przekaz jest taki, że polecenie find dostarcza listę plików które spełniają pewne kryteria. Lista ta jest następnie przekazywana do polecenia xargs, które następnie uaktywnia inne polecenie z listą plików jako argumentami, tak jak w przykładzie:

Listing 13. Przykład klasycznego zastosowania xargs

~ $ find some-file-criteria some-file-path | > xargs some-great-command-that-needs-filename-arguments

Jednakże nie należy myśleć że xargs jest "tylko" pomocnikiem dla find; jest to jedno z tych niedocenionych, nieużywanych narzędzi, które jak tylko nauczysz się ich używać, będziesz chciał je wypróbować na wszystkim, na przykład tak jak tutaj:

Stworzenie listy oddzielonej spacjami

W tym najprostszym zastosowaniu xargs jest jak filtr, który przyjmuje jako dane wejściowe listę plików (każdy element listy w oddzielnej linii). Następnie kolejne polecenie tworzy z tych elementów jedną linię rozdzieloną spacjami:

Listing 14. Przykład zastosowania xargs

~ $ xargs
a
b
c
Control-D
a b c
~ $

Możesz wysłać wynik działania każdej komendy, która pokazuje nazwę pliku, do xargs aby otrzymać listę argumentów dla innego polecenia które wymaga nazwy pliku jako argumentu, tak jak w poniższym przykładzie:

Listing 15. Przykład użycia xargs

~/tmp $ ls -1 | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
~/tmp $ ls -1 | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable
~/tmp $

Polecenie xargs jest używane nie tylko do przekazywania nazw plików. Używaj go za każdym razem kiedy potrzebujesz zamienić tekst w ciągłą linię:

Listing 16. Przykład dobrego nawyku nr.7: Użycie xargs do zamiany tekstu w ciągłą linię

~/tmp $ ls -l | xargs
-rw-rr 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-rr 1 root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 16:07 a -rw-rr 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 joe joe 3239 Sep 30 12:40 mkdirhier.sh
~/tmp $

Bądź ostrożny używając xargs

Technicznie rzecz biorąc, rzadko może zdarzyć się sytuacja, kiedy używając xargs możesz wpaść w kłopoty. Domyślnie każdy plik jest zakończony znakiem podkreślenia (_)(EOF string); jeśli ten znak jest wysłany jako pojedynczy argument dla xargs, wszystko poza nim jest ignorowane. Jako zabezpieczenie przed tą sytuacją, używaj znacznika -e, który, bez żadnych dodatkowych argumentów wyłącza całkowicie znak zakończenia pliku.

Wiedz kiedy użyć grep, a kiedy nie.

Unikaj łączenia w jednym potoku (pipe) łączenia grep z wc -l aby obliczyć ilość linii w danych wyjściowych. Użycie opcji -c wraz z poleceniem grep umożliwia obliczenie ilości linii które odpowiadają wybranemu wzorcowi, a poza tym jest to rozwiązanie szybsze niż przekierowanie do wc, tak jak w poniższym przykładzie:

Listing 17. Przykład dobrego nawyku nr 8.: Liczenie linii z i bez grep

~ $ time grep and tmp/a/longfile.txt | wc -l
2811

real 0m0.097s
user 0m0.006s
sys 0m0.032s
~ $ time grep -c and tmp/a/longfile.txt
2811

real 0m0.013s
user 0m0.006s
sys 0m0.005s
~ $

Poza prędkością, opcja -c jest też lepszym sposobem na liczenie. Mając do czynienia z wieloma plikami, grep -c zwraca wynik liczony oddzielnie dla każdego pliku, każdy w pojedynczej linii; podczas gdy grep w połączeniu z wc podaje całkowitą liczbę dla wszystkich plików razem.

Jednakże, bez względu na prędkość, podane przykłady pokazują kolejny, powszechny, błąd którego należy unikać. Te sposoby podają jedynie liczbę linii które zawierają wybrany wzorzec — i jeśli to jest to czego szukasz, to świetnie. Ale w przypadku gdy linie mają kilka wariantów wzorca którego szukasz, metody te nie podają prawdziwej liczby [wariantów szukanego wzorca]. Aby policzyć liczbę wariantów, mimo wszystko używaj wc. Najpierw użyj grep z opcją -o, jeśli tylko twoja wersja grep na to pozwala. Ta opcja ukazuje tylko szukane wyrażenie, każde w oddzielnej linii, ale nie linie same w sobie. Niestety nie możesz użyć tej opcji wraz z -c, a więc używaj wc -l, tak jak w poniższym przykładzie:

Listing 18. Przykład dobrego nawyku nr 8.: Liczenie wariantów wzorca używając grep

~ $ grep -o and tmp/a/longfile.txt | wc -l
3402
~ $

W tym przypadku, wywołanie do wc jest trochę szybsze niż ponowne wywołanie grep z szukanym wzorcem który próbowałby dopasowywać i liczyć każdą linię (np.: grep -c)

Porównuj nie tylko linie, ale i konkretne pola w danych wyjściowych.

Komenda taka jak awk jest preferowana do używania wraz z poleceniem grep, gdy chcesz znaleźć szukany wzorzec w konkretnym polu w linii a nie gdziekolwiek w danych wyjściowych.

Poniższy uproszczony przykład pokazuje jak znaleźć i pokazać tylko te pliki, które były modyfikowane w grudniu:

Listing 19. Przykład złego nawyku nr 9.: Użycie grep do znalezienia wzorca w konkretnym polu

~/tmp $ ls -l /tmp/a/b/c | grep Dec
r-w-rr 7 joe joe 12043 Jan 27 20:36 December_Report.pdf
-rw-rr 1 root root 238 Dec 03 08:19 README
-rw-rr 3 joe joe 5096 Dec 14 14:26 archive.tar
~/tmp $

W tym przykładzie, polecenie grep filtruje linie danych wyjściowych, wyświetlając wszystkie pliki z nazwą Dec w datach modyfilacji, jak też i w nazwach plików. Dlatego też plik December_Report.pdf został pokazany, pomimo iż nie był on modyfikowany od stycznia. To raczej nie jest to czego oczekujesz. Aby odnaleźć szukaną frazę w konkretnym miejscu lepiej jest użyć awk, gdzie *relational operator*odpowiada konkretnemu polu, tak jak w przykładzie:

Listing 20. Przykład dobrego nawyku nr 9.: Używanie awk do znajdowania frazy w konretnych polach

~/tmp $ ls -l | awk '$6 == "Dec"'
-rw-rr 3 joe joe 5096 Dec 14 14:26 archive.tar
-rw-rr 1 root root 238 Dec 03 08:19 README
~/tmp $

Przejrzyj literaturę źródłową aby poznać szczegóły na temat używania awk

Przestań nadużywać cat w przetwarzaniu potokowym/potokach.

Prostym ale i powszechnym błędem w użytkowaniu polecenia grep jest przetwarzanie przez grep danych wcześniej obrabianych przez polecenie cat aby w ten sposób przeszukać zawartość pliku. Jest to zbędne i przede wszystkim jest to strata czasu, ponieważ polecenie grep jako argumentu używa nazwy pliku. Po prostu nie musisz używać cat w tym przypadku, tak jak w poniższym przykładzie:

Listing 21. Przykład dobrego i złego nawyku nr 10.: Używanie grep z i bez cat

~ $ time cat tmp/a/longfile.txt | grep and
2811

real 0m0.015s
user 0m0.003s
sys 0m0.013s
~ $ time grep and tmp/a/longfile.txt
2811

real 0m0.010s
user 0m0.006s
sys 0m0.004s
~ $

Ten błąd jest charakterystyczny dla wielu poleceń. Ponieważ większość poleceń przyjmuje *standard input* z myślnikiem (-) i argumentem, więc nawet głos za używaniem cat aby zamiast *stdin/standard input* używać nazwy pliku nie ma pokrycia. Jest to jedynie uzasadnione jeśli chcemy polecenia używane w potoku użyć wraz z komendą cat i jedną z jej kilku opcji filtrujących.

Podsumowanie: Nabywaj dobrych nawyków

Jest rzeczą pożądaną abyś zbadał swoje nawyki przy pracy z linią poleceń, w celu wykrycia jakiś złych wzorców. Złe nawyki spowolniają pracę i często prowadzą do niespodziewanych błędów. Artykuł ten prezentuje dziesięć nowych wzorców które mogą Ci pomóc uwolnić się od najczęstszych błędów. Nabycie tych dobrych wzorców jest pozytywnym krokiem w kierunku doskonalenia umiejętności obsługi UNIX-owej liniii poleceń.

Źródła:

* "Use free software within commercial UNIX" (developerWorks, February 2006) krótki elementarz nt.używania aplikacji open source na komercyjnym i własnościowym systemie UNIX.

* "Working in the bash shell" (developerWorks, May 2006) wprowadzenie do Bash.

* "Get started with GAWK" (developerWorks, September 2006) jak posługiwać się językiem AWK przy edycji tekstu.

* "Hone your regexp pattern-building skills" (developerWorks, July 2006) opis jak efektywniej wykorzystać polecenie grep.

* Odwiedź the developerWorks AIX and UNIX zone gdzie znajdziesz materiały dzięki którym zwiększysz swoje umiejętności.

* Zacząłeś używać AIX i UNIX? Odwiedź the developerWorks New to AIX and UNIX aby nauczyć się czegoś więcej.

* Rozglądnij się w księgarni technicznej za książkami na podane i inne tematy.

Produkty i technologie

* Chcąc uzyskać kopię mkdirhier, możesz pobrać wersję z *the Haskell compiler*

O autorze

Michael Stutz jest autorem "The Linux Cookbook", którą, przez przypadek, zaprojektował i napisał używając jedynie oprogramowania Open Source. Jego zainteresowania badawcze dotyczą publlikacji cyfrowych i przyszłości książek. Używa różnych systemów UNIX od 20 lat. Jest dostępny pod adresem e-mail: gro.lsd|ztuts#gro.lsd|ztuts.

Tłumaczenie z j. angielskiego - Marek M. Żemajduk


komentarze, sugestie tłumacza


escape sequences jak to przetłumaczyć?
relational operator
standard input
the Haskell Compiler


Dodaj nową wypowiedź
lub Zaloguj się jako użytkownik serwisu Wikidot.com
(nie będzie opublikowany)
- +
O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-NonCommercial 3.0 License