Gentoo Logo

Uwaga: Oryginalna wersja tego artykułu została opublikowana w IBM developerWorks i jest własnością Westtech Information Services. Poniższy dokument jest poprawioną przez zespół GDP wersją oryginalnego tekstu i nie jest już aktualizowany.


Przygotowanie do egzaminu LPI 101 (wydanie 2), część 2

Spis treści:

1.  Zanim zaczniemy

O tym artykule

Witajcie w "podstawach administracji" - drugim z serii czterech artykułów, napisanych, aby przygotować was do egzaminu LPI 101. W tej części dowiemy się jak znajdować ciągi znaków w plikach posługując się wyrażeniami regularnymi, następnie poznamy standardową hierarchię systemu plików (FHS) oraz nauczymy się jak znajdować pliki w naszym systemie. Potem zajmiemy się kontrolowaniem procesów w Linuksie - m.in. nauczymy się uruchamiać procesy w tle, wyświetlać ich listę oraz odłączać je od terminala. Następnie przejdziemy przyspieszony kurs obsługi wątków, przekierowywania oraz zapoznamy się z polecieniami służącymi do przetwarzania tekstu. Na koniec dowiemy się co nieco na temat modułów jądra Linuksa.

Ta część naszego kursu jest skierowana do ludzi mających już ugruntowane podstawy basha, którzy chcą otrzymać solidną dawkę informacji dotyczących podstaw administrowania systemem Linux. Jeżeli nie mieliśmy jeszcze okazji zapoznać się z Linuksem, dobrze by było, gdybyśmy najpierw przeczytali pierwszą część tego kursu, zanim przejdziemy do dalszej lektury. Dla niektórych z nas spora część zawartych w tym artykule informacji będzie nowa, natomiast ci, którzy są już bardziej doświadczonymi użytkownikami Linuksa, mogą potraktować ten artykuł jako dobry sposób na szlifowanie swoich umiejętności.

Ci z nas, którzy przeczytali pierwszą wersję tego artykułu z powodów innych niż przygotowywanie się do egzaminu LPI, raczej nie muszą jej czytać powtórnie. Aczkolwiek jeżeli planujemy podejść do tego egzaminu, przeczytanie tej poprawionej wersji artykułu jest wskazane.

O autorze

Daniel Robins zamieszkujący w Albuquerque, w stanie Nowy Meksyk, jest głównym architektem dystrybucji Gentoo Linuks. Zajmuje się także pisaniem artykułów dla strefy Linuksa na IBM Developer Works oraz dla Intel Developer Services. Jest także współautorem kilku książek, wliczając w to Samba Unleashed, Suse Unleashed oraz Linux Unleashed. Daniel lubi spędzać czas ze swoją żoną Mary oraz ze swoją małą córeczką Hadassah. Możemy się z nim skontaktować pisząc na adres poczty elektronicznej Daniel Robbins.

Chris Houser, wśród przyjaciół znany jako "Chouser", głosi idee UNIX-a już od 1994 roku, kiedy to przyłączył się do zespołu administratorów sieci naukowej na uniwersytecie Taylora w stanie Indiana, gdzie zrobił licencjat z informatyki i matematyki. Od tamtej pory pracował jako programista aplikacji internetowych, projektant interfejsów użytkownika oraz serwisant profesjonalnych programów do obróbki video. Obecnie zajmuje się programowianiem sterowników urządzeń dla wersji Tru64 systemu UNIX w firmie Compaq. Był także uczestnikiem wielu projektów programistycznych (ostatnio projektu Gentoo Linux). Mieszka w New Hampshire razem ze swoją żoną i dwoma kotami. Możemy się z nim skontaktować pisząc na adres poczty elektronicznej Chris Houser

Aron Griffis ukończył uniwersytet Taylora ze stopniem naukowym z informatyki. Otrzymał też nagrodę której nazwa brzmi "Przyszły założyciel utopijnej UNIX-owej komuny". Pracując w duchu tej nagrody Aron zajmuje się programowaniem sterowników sieciowych dla wersji Tru64 systemu UNIX w firmie Compaq, w wolnym czasie brzdąkając na pianinie oraz rozwijając projekt Gentoo. Mieszka w Nashua, w New Hampshire, razem ze swoją żoną Amy (która także jest programistą UNIX-owym).

2.  Wyrażenia regularne

Czym są wyrażenia regularne?

Wyrażenie regularne (nazywane także "regex" lub "regexp") jest specjalną składnią, służącą do opisu wzorców tekstowych. Na systemach linuksowych, wyrażenia regularne są powszechnie używane zarówno do znajdowania określonych fragmentów tekstu pasujących do wzorca, jak również aby wykonywać operacje typu "znajdź i zamień" na strumieniach tekstowych.

Porównanie ze znakami zastępczymi ("globami")

Przyglądając się wyrażeniom regularnym, spostrzeżemy za pewne, że ich składnia jest bardzo podobna do tej, której używaliśmy w pierwszej części tego kursu, do "globowania" w nazwach plików. Nie dajmy się jednak zmylić - ich podobieństwo jest powierzchowne. Podczas gdy zarówno wyrażenia regularne jak i znaki zastępcze mogą wydawać się identyczne, w rzeczywistości zasadniczo się od siebie różnią.

Zwyczajny fragment ciągu znaków

Mając to na uwadze przyjrzyjmy się najprostszemu z wyrażeń regularnych - zwykłemu wycinkowi ciągu znaków. Pomoże nam w tym grep - polecenie z którego pomocą możemy przeszukiwać zawartość plików tekstowych w poszukiwaniu fragmentów tekstu, pasujących do danych wyrażeń regularnych. grep wydrukuje każdą linijkę która będzie pasowała do szukanego wyrażenia regularnego, zignoruje natomiast wszystkie pozostałe:

Listing 2.1: grep w akcji

$ grep bash /etc/passwd
operator:x:11:0:operator:/root:/bin/bash
root:x:0:0::/root:/bin/bash
ftp:x:40:1::/home/ftp:/bin/bash

Powyżej pierwszym parametrem przekazanym do polecenia grep jest wyrażenie regularne, drugim jest nazwa pliku. grep odczyta każdą linijkę z pliku /etc/passwd i sprawdzi czy występuje w niej szukany fragment tekstu. Jeżeli powyższy fragment zostanie odnaleziony, grep wydrukuje całą, zawierającą go linie; w innym wypadku linia zostanie zignorowana.

Zasada działania zwykłego fragmentu tekstu

W gruncie rzeczy jeżeli szukamy fragmentu tekstu, możemy po prostu podać go bez żadnych "specjalnych" znaków. Dodatkowe zabiegi będą potrzebne jedynie wtedy, gdy którymś z szukanych przez nas znaków będzie +, ., *, [, ] lub \. W przypadku tych znaków będziemy musieli poprzedzić je lewym ukośnikiem, a całe wyrażenie umieścić w cudzysłowach. Oto kolejne przykłady prostych wyrażeń regularnych:

  • /tmp (szuka ciągu /tmp)
  • "\[box\]" (szuka ciągu [box])
  • "\*funny\*" (szuka ciągu *funny*)
  • "ld\.so" (szuka ciągu ld.so)

Metaznaki

Używając wyrażeń regularnych możemy wykonywać znacznie bardziej skomplikowane przeszukiwania od tych które widzieliśmy do tej pory. Umożliwiają to metaznaki. Jednym z nich jest . (kropka) która jest odpowiednikiem dowolnego pojedyńczego znaku:

Listing 2.2: Metaznak: kropka

$ grep dev.hda /etc/fstab
/dev/hda3       /               reiserfs        noatime,ro 1 1
/dev/hda1       /boot           reiserfs        noauto,noatime,notail 1 2
/dev/hda2       swap            swap            sw 0 0
#/dev/hda4      /mnt/extra      reiserfs        noatime,rw 1 1

W powyższym przykładzie dokładny tekst dev.hda nie pojawił się w żadnej linii w pliku /etc/fstab. Jednakże grep nie przeszukiwał ich w poszukiwaniu ciągu identycznego z dev.hda, a w poszukiwaniu szablonu dev.hda. Musimy pamiętać, że . zostanie z powodzeniem przyrównana do dowolnego, pojedyńczego znaku. Jak widać metaznak . w sferze funkcjonalności jest porównywalny do metaznaku ? znanego nam z rozwinięć w znakach zastępczych.

Używanie []

Jeżeli chcemy zdefiniować szukany znak trochę bardziej precyzyjnie niż pozwala na to kropka, możemy użyć [ oraz ] (nawiasów kwadratowych), aby określić zbiór znaków które powinny zostać znalezione:

Listing 2.3: Nawiasy kwadratowe w akcji

$ grep dev.hda[12] /etc/fstab
/dev/hda1       /boot           reiserfs        noauto,noatime,notail 1 2
/dev/hda2       swap            swap            sw 0 0

Jak widać ta konstrukcja syntaktyczna działa identycznie do poznanej przez nas podczas omawiania znaków zastępczych sekwencji []. To jest właśnie jedną z trudności jakie napotykamy podczas nauki wyrażeń regularnych - składnia jest podobna ale nie identyczna do składni znaków zastępczych, co często sprawia trudności podczas nauki.

Używanie [^]

Możemy zanegować znaczenie nawiasów kwadratowych poprzez umieszczenie ^ jako pierwszego znaku po [. W tym wypadku nawiasy będą odpowiadały każdemu znakowi, który nie jest wypisany między nimi. Ponownie warto odnotować, że sekwencji [^] używamy jako wyrażenia regularnego, której odpowiednikiem dla znaków zastępczych jest [!]:

Listing 2.4: Zanegowane nawiasy

$ grep dev.hda[^12] /etc/fstab
/dev/hda3       /               reiserfs        noatime,ro 1 1
#/dev/hda4      /mnt/extra      reiserfs        noatime,rw 1 1

Różnice składniowe

Bardzo ważne jest to, że składnia wewnątrz nawiasów kwadratowych różni się w sposób zasadniczy od tej, używanej w innych częściach wyrażenia regularnego. Na przykład, jeżeli umieścimy . wewnątrz nawiasów kwadratowych, sekwencja ta będzie odpowiadała znakowi kropki, tak samo jak cyfry 1 i 2 w powyższym przykładzie. Dla porównania . umieszczona na zewnątrz nawiasów kwadratowych zostanie zinterpretowana jako metaznak, chyba że poprzedzimy ją znakiem "\". Możemy to wykorzystać do wypisania wszystkich linii z /etc/fstab, które zawierają dokładny ciąg dev.hda, wykonując następujące polecenie:

Listing 2.5: Szukanie konkretnych znaków za pomocą nawiasów

$ grep dev[.]hda /etc/fstab

Moglibyśmy to także zrobić w ten sposób:

Listing 2.6: Szukanie konkretnych znaków za pomocą sekwencji ucieczki

$ grep "dev\.hda" /etc/fstab

Żadne z powyższych wyrażeń regularnych nie będzie pasowało do którejkolwiek linii w pliku /etc/fstab

Metaznak "*"

Niektóre metaznaki jako takie, nie mają konkretnego znaczenia, natomiast wpływają one na znaczenie znaków poprzednich. Jednym z takich metaznaków jest * (gwiazdka), której używamy aby zdefiniować zero lub więcej wystąpień poprzedzającego ją znaku. Warto odnotować, że * ma inme znaczenie w wyrażeniach regularnych od tego w znakach zastępczych. Oto kilka przykładów demonstrujących te różnice:

  • ab*c odpowiada abbbbc ale nie abqc (jeżeli byłby to znak zastępczy, oba ciągi zostałyby dopasowane - czy wiemy dlaczego?)
  • ab*c odpowiada abc ale nie abbqbbc (ponownie, gdyby to był znak zastępczy oba wyrażenia zostałyby dopasowane)
  • ab*c odpowiada ac ale nie cba (w przypadku znaków zastępczych, żaden z ciągów nie odpowiadał by wzorcowi)
  • b[cq]*e odpowiada bqe oraz be (w przypadku znaków zastępczych, wzorzec pasował by do bqe ale nie do be)
  • b[cq]*e odpowiada bccqqe ale nie bccc (w przypadku znaków zastępczych będzie podobnie - pierwszy ciąg będzie pasował do wzorca, drugi nie)
  • b[cq]*e odpowiada bqqcce ale nie cqe (podobnie jak poprzednio, w przypadku znaków zastępczych wzorzec będzie pasował do pierwszego ciągu, natomiast do drugiego już nie)
  • b[cq]*e odpowiada bbbeee (nie jest to prawdą w przypadku znaków zastępczych)
  • .* odpowiada dowolnemu ciągowi (w przypadku znaków zastępczych odpowiada to dowolnemu ciągowi, rozpoczynającemu się od .)
  • foo.* odpowiada dowolnemu ciągowi rozpoczynającemu się od foo (w przypadku znaków zastępczych odpowiada to dowolnemu ciągowi rozpoczynającemu się od czteroznakowego ciągu foo. )

Teraz szybkie powtórzenie: linia ac odpowiada wyrażeniu regularnemu ab*c ponieważ gwiazdka pozwala na to, aby poprzedzający ją znak (b) występował zero razy. Jest to fundamentalna różnica między * w wyrażeniach regularnych, a * w znakach zastępczych. Musimy to zapamiętać.

Początek i koniec linii

Ostatnimi z metaznaków które poznamy, są ^ i $, używane do oznaczenia odpowiednio początku i końca linii. Używając ^ na początku naszego wyrażenia regularnego sprawimy, że nasze wyrażenie będzie "zakotwiczone" na początku linii. W przykładzie poniżej użyjemy ^#, aby znaleźć linie rozpoczynające się od znaku # (hash):

Listing 2.7: Linie

$ grep ^# /etc/fstab
# /etc/fstab: static file system information.
#

Wyrażenia regularne obejmujące całe linie

Znaki ^ oraz $ mogą być łączone aby dopasowywać się do całej linii. Jako przykład, poniższe wyrażenie odnajdzie linie rozpoczynające się od znaku # i kończące sie znakiem . z dowolną ilością znaków pomiedzy nimi.

Listing 2.8: Dopasowywanie całej linii

$ grep '^#.*\.$' /etc/fstab
# /etc/fstab: static file system information.

W powyższym przykładzie otoczyliśmy nasze wyrażenie pojedyńczymi cudzysłowami aby zapobiec interpretowaniu znaku $ przez powłokę. Jeżeli byśmy tego nie zrobili, znak $ zniknął by z naszego wyrażenia i grep nigdy by go nie zobaczył.

3.  FHS i znajdowanie plików

Standard hierarchii systemu plików (FHS)

Standard hierarchii systemu plików (Filesystem Hierarchy Standard) jest dokumentem który opisuje strukturę katalogów w systemach linuksowych. FHS został stworzony po to, by dostarczać standardowy układ katalogów, aby uprościć rozwijanie oprogramowania - wszystko powinno być tam gdzie się tego spodziewamy, niezależnie od dystrybucji Linuksa. FHS definiuje następującą strukturę drzewa katalogów (zaczerpnięto bezpośrednio ze specyfikacji FHS):

  • / (katalog główny)
  • /boot (pliki statyczne boot loadera)
  • /dev (pliki urządzeń)
  • /etc (konfiguracja systemu)
  • /lib (podstawowe biblioteki współdzielone oraz moduły jądra)
  • /mnt (punkt montowania tymczasowych systemów plików)
  • /opt (dodatkowe pakiety aplikacji)
  • /sbin (podstawowe biblioteki systemowe)
  • /tmp (pliki tymczasowe)
  • /usr (drugorzędna hierarchia)
  • /var (zmienne dane)

Dwie niezależne kategorie FHS

U podstaw FHS stoi zasada, że są dwie niezależne kategorie plików: te które możemy współdzielić między hostami kontra te dla których nie jest to możliwe (dane specyficzne dla danego hosta, np. pliki konfiguracyjne) oraz zmienne dane (które podlegają modyfikacjom) kontra dane statyczne (które nie są modyfikowane, pomijając instalację i konserwację systemu).

Poniższa tabela pokazuje wszystkie cztery kombinacje, z przykładowymi katalogami które podpadają pod dane kategorie. Tabela, podobnie jak drzewo katalogów, jest żywcem wzięta ze specyfikacji FHS.

Listing 3.1: FHS

+---------+-----------------+------------------+
|         | współdzielone   | niewspółdzielone |
+---------+-----------------+------------------+
|statyczne| /usr            | /etc             |
|         | /opt            | /boot            |
+---------+-----------------+------------------+
|zmienne  | /var/mail       | /var/run         |
|         | /var/spool/news | /var/lock        |
+---------+-----------------+------------------+

Drugorzędna hierarchia w /usr

Wchodząc do katalogu /usr zobaczymy hierarchię bardzo podobną do tej w katalogu głównym. Istnienie /usr nie jest wymagane podczas startu systemu, dlatego też możemy współdzielic ten katalog poprzez sieć (współdzielony) bądź montować go z płyty CD (statyczny). Większość instalatorów Linuksa nie kożysta ze współdzielenia /usr, ale jest dla nas ważne aby rozróżniać pierwszorzędną hierarchię w katalogu głównym od drugorzędnej znajdującej się w /usr.

To już wszystkie informacje o FHS w tym artykule. Sam dokument jest dosyć czytelny i warto było by do niego zajrzeć. Jego lektura pozwoli nam dużo lepiej poznać system plików Linuksa. Dokument można znaleźć tutaj: http://www.pathname.com/fhs/.

Znajdowanie plików

Linuksowy system plików zawiera zwykle setki tysięcy plików. Być może niektórzy z nas pamiętają co gdzie wrzucili, natomiast reszta śmiertelników od czasu do czasu będzie potrzebowała drobnej pomocy żeby coś znaleźć. Na Linuksie jest kilka różnych narzędzi które służą do szukania plików. To wprowadzenie pomoże nam wybrać odpowiednie z nich do danego zadania.

Ścieżka (PATH)

Kiedy uruchamiamy program z linii poleceń, tak naprawdę bash przegląda kolejne katalogi w poszukiwaniu programu który chcemy uruchomić. Na przykład kiedy napiszemy ls, bash nie wie o tym instynktownie, że program ls znajduje się w /usr/bin. Pobiera on natomiast listę ze zmiennej środowiskowej PATH, zawierającą oddzielone od siebie dwukropkiem nazwy katalogów. Możemy przeanalizować zawartość zmiennej PATH:

Listing 3.2: Wyświetlanie zmiennej PATH

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin

Przy takiej zawartości zmiennej PATH (nasza może się różnić), bash sprawdzi najpierw /usr/local/bin, a potem /usr/bin w poszukiwaniu programu ls. Zazwyczaj ls znajduje się w /usr/bin, więc bash nie będzie szukał dalej.

Modyfikacja zmiennej PATH

Możemy powiększyć zawartość zmiennej PATH za pomocą przypisania w linii poleceń:

Listing 3.3: Edycja zmiennej PATH

$ PATH=$PATH:~/bin
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/home/agriffis/bin

Możemy także usuwać poszczególne elementy ze zmiennej PATH, ale nie jest to już takie proste, ponieważ nie możemy używać aktualnej wartości tej zmiennej. Najprościej jest po prostu wpisać nową wartość PATH:

Listing 3.4: Usuwanie wpisów z PATH

$ PATH=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:~/bin
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/agriffis/bin

Aby nasze zmiany były widoczne dla każdego programu odpalonego później z tej konsoli, musimy wyeksportować wartość zmiennej PATH:

Listing 3.5: Eksportowanie PATH (lub jakiejkolwiek innej zmiennej)

$ export PATH

Wszystko o "which"

Możemy sprawdzić czy dany program znajduje się w którymś z katalogów wpisanych do PATH, za pomocą polecenia which. Na przykład żeby odkryć, że nasz system nie ma sensu, wystarczy napisać:

Listing 3.6: Poszukiwania sensu

$ which sense
which: no sense in (/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin)

W tym przykładzie z powodzeniem zlokalizujemy ls:

Listing 3.7: Szuknie ls

$ which ls
/usr/bin/ls

"which -a"

Na koniec powinniśmy zwrócić uwagę na opcję -a która powoduje, że which pokaże wszystkie znalezione kopie danego programu w katalogach z PATH:

Listing 3.8: Znajdowanie wszystkich kopii programu w PATH-u

$ which -a ls
/usr/bin/ls
/bin/ls

whereis

Jeżeli chcemy dowiedzieć się czegoś więcej o programie, poza jego lokacją, możemy użyć polecenia whereis:

Listing 3.9: Użycie whereis

$ whereis ls
ls: /bin/ls /usr/bin/ls /usr/share/man/man1/ls.1.gz

Widzimy, że ls występuje w katalogach /bin oraz /usr/bin które są standardową lokacją dla plików binarnych. Polecenie whereis informuje nas także o istnieniu strony podręcznika systemowego, zlokalizowanej w /usr/share/man, której zawartość zobaczymy po wpisaniu man ls.

Program whereis potrafi także szukać źródeł, można zdefiniować dla niego alternatywne ścieżki do przeszukania, można też z jego pomocą szukać nietypowych pozycji. Jeżeli chcemy dowiedzieć się więcej na temat tego polecenia, najlepiej skorzystac z man whereis.

find

Polecenie find jest kolejnym przydatnym narzędziem, które jako pierwsze nie ogranicza się do szukania programów - możemy szukać dowolnego pliku, używając najróżniejszych kryteriów przeszukiwania. Możemy na przykład szukać pliku o nazwie README rozpoczynając w /usr/share/doc:

Listing 3.10: Używanie find

$ find /usr/share/doc -name README
/usr/share/doc/ion-20010523/README
/usr/share/doc/bind-9.1.3-r6/dhcp-dynamic-dns-examples/README
/usr/share/doc/sane-1.0.5/README

find i znaki zastępcze (globy)

Możemy używać globów jako argumentu razem z -name, pod warunkiem, że ujmiemy je w cudzysłowy bądź użyjemy sekwencji ucieczki, dzieki czemu nie zostaną zinterpretowane przez basha. W poniższym przykładzie szukamy plików README z dowolnym rozszerzeniem:

Listing 3.11: Użycie find z globami

$ find /usr/share/doc -name README\*
/usr/share/doc/iproute2-2.4.7/README.gz
/usr/share/doc/iproute2-2.4.7/README.iproute2+tc.gz
/usr/share/doc/iproute2-2.4.7/README.decnet.gz
/usr/share/doc/iproute2-2.4.7/examples/diffserv/README.gz
/usr/share/doc/pilot-link-0.9.6-r2/README.gz
/usr/share/doc/gnome-pilot-conduits-0.8/README.gz
/usr/share/doc/gimp-1.2.2/README.i18n.gz
/usr/share/doc/gimp-1.2.2/README.win32.gz
/usr/share/doc/gimp-1.2.2/README.gz
/usr/share/doc/gimp-1.2.2/README.perl.gz
[obcięto 578 pozostałych linii]

Ignorowanie wielkości liter podczas szukania

Oczywiście możemy zażądać, aby find nie zwracał uwagi na wielkość liter:

Listing 3.12: Ignorowanie wielkości liter w find

$ find /usr/share/doc -name '[Rr][Ee][Aa][Dd][Mm][Ee]*'

Jest też na to dużo prostszy sposób:

Listing 3.13: Inny sposób

$ find /usr/share/doc -iname readme\*

Jak widać możemy użyć argumentu -iname aby find ignorował wielkość liter.

find i wyrażenia regularne

Jeżeli czujemy się pewnie korzystając wyrażeń regularnych, możemy ich używać z find - pozwala nam na to argument -regex. Wynik działania find zostanie przefiltrowany w poszukiwaniu danego wyrażenia regularnego. Podobnie jak w przypadku zwykłej nazwy, możemy przekazać do programu find polecenie, aby ignorował wielkość znaków w wyrażeniu regularnym, za pomocą opcji -iregex. Oto przykład:

Listing 3.14: Wyrażenia regularne i find

$ find /etc -iregex '.*xt.*'
/etc/X11/xkb/types/extra
/etc/X11/xkb/semantics/xtest
/etc/X11/xkb/compat/xtest
/etc/X11/app-defaults/XTerm
/etc/X11/app-defaults/XTerm-color

Ważne jest by zapamiętać, że w przypadku polecenia find nasze wyrażenie regularne musi pasować do całej linii, a nie tylko do małego jej fragmentu. Dlatego właśnie konieczne jest używanie .* na początku i na końcu naszego wyrażenia. Użycie samego xt jako regexpa nie dało by oczekiwanych rezultatów.

find i typy obiektów

Opcja -type pozwala nam szukać danego typu obiektu w systemie plików. Mamy do dyspozycji następujące typy: b (urządzenie blokowe), c (urządzenie znakowe), d (katalog), p (nazwany potok), f (zwykły plik), l (dowiązanie symboliczne) oraz s (gniazdo/socket). Jeżeli chcielibyśmy na przykład znaleźć dowiązania symboliczne w /usr/bin które zawierają ciąg "vim":

Listing 3.15: Ograniczanie find do danego typu

$ find /usr/bin -name '*vim*' -type l
/usr/bin/rvim
/usr/bin/vimdiff
/usr/bin/gvimdiff

find i mtimes

Opcja -mtime pozwala znajdować pliki na podstawie czasu ich ostatniej modyfikacji. Jako argument podajemy przedział czasu (jednostką jest doba) który najlepiej poprzedzić znakiem plus, oznaczającym "później" lub znakiem minus oznaczającym oczywiście "wcześniej". Rozważmy następujący scenariusz:

Listing 3.16: Scenariusz

$ ls -l ?
-rw-------    1 root     root            0 Jan  7 18:00 a
-rw-------    1 root     root            0 Jan  6 18:00 b
-rw-------    1 root     root            0 Jan  5 18:00 c
-rw-------    1 root     root            0 Jan  4 18:00 d
$ date
Mon May  7 18:14:52 EST 2003

Możemy np. szukać plików utworzonych w ciągu ostatniej doby:

Listing 3.17: Pliki stworzone w ciągu ostatniej doby

$ find . -name \? -mtime -1
./a

Możemy też znaleźć te, utworzone ponad 24 godziny temu:

Listing 3.18: Pliki stworzone wcześniej niż 24 godziny temu

$ find . -name \? -mtime +0
./b
./c
./d

Opcja -daystart

Jeżeli dodatkowo podamy opcję -daystart, okresy czasu będą się zaczynać od początku dzisiejszego dnia, a nie tak jak do tej pory od chwili obecnej. Jako przykład - kilka plików stworzonych wczoraj i przedwczoraj:

Listing 3.19: Używamy -daystart

$ find . -name \? -daystart -mtime +0 -mtime -3
./b
./c
$ ls -l b c
-rw-------    1 root     root            0 May  6 18:00 b
-rw-------    1 root     root            0 May  5 18:00 c

Opcja -size

Opcja -size pozwala nam lokalizować pliki na podstawie ich rozmiaru. Standardowo jako argument podaje się liczbę 512-sto bajtowych bloków, ale możemy to zmienić dodając przyrostek: b (512-sto bajtowe bloki), c (bajty), k (kilobajty) oraz w (2-bajtowe słowa). Tu także możemy dopisać znak plus ("większy niż") lub minus ("mniejszy niż").

W tym przykładzie szukamy zwykłych plików w /usr/bin, mniejszych niż 50 bajtów:

Listing 3.20: Opcja -size w akcji

$ find /usr/bin -type f -size -50c
/usr/bin/krdb
/usr/bin/run-nautilus
/usr/bin/sgmlwhich
/usr/bin/muttbug

Przetwarzanie znalezionych plików

Polecenie find daje nam także możliwość przetwarzania znalezionych plików - służy do tego opcja -exec. Możemy jej przekazać jako argument dowolne polecenie zakończone średnikiem, a każde wystąpienie {} zostanie zastąpione nazwą kolejnych znalezionych plików. Najprościej to zrozumieć patrząc na poniższy przykład:

Listing 3.21: Używamy -exec

$ find /usr/bin -type f -size -50c -exec ls -l '{}' ';'
-rwxr-xr-x    1 root     root           27 Oct 28 07:13 /usr/bin/krdb
-rwxr-xr-x    1 root     root           35 Nov 28 18:26 /usr/bin/run-nautilus
-rwxr-xr-x    1 root     root           25 Oct 21 17:51 /usr/bin/sgmlwhich
-rwxr-xr-x    1 root     root           26 Sep 26 08:00 /usr/bin/muttbug

Jak widać find jest potężną komendą. Rozwijała się przez lata, razem z UNIX-em i Linuksem. Posiada jeszcze wiele użytecznych opcji o których możemy poczytać na stronach podręcznika systemowego.

locate

Mówiliśmy już o which, whereis i find. Mogliśmy zauważyć, że wykonanie się polecenia find może zająć trochę czasu, ponieważ musi ono odczytać zawartość każdego katalogu podczas jego przeszukiwania. Okazuje się, że polecenie locate może przyspieszyć proces szukania, ponieważ korzysta ono z zewnętrznej bazy danych wygenerowanej przez polecenie updatedb (którym zajmiemy się w następnym akapicie).

Polecenie locate dopasowuje szukaną frazę do dowolnej części ścieżki prowadzącej do pliku, nie zaś do samej jego nazwy:

Listing 3.22: locate w akcji

$ locate bin/ls
/var/ftp/bin/ls
/bin/ls
/sbin/lsmod
/sbin/lspci
/usr/bin/lsattr
/usr/bin/lspgpot
/usr/sbin/lsof

Używamy updatedb

Większość systemów linuksowych ma dopisane do crontaba polecenie aktualizujące baze danych co pewien czas. Jeżeli locate zwraca nam błąd taki jak poniżej, będziemy musieli uruchomić updatedb jako root aby wygenerować tę bazę:

Listing 3.23: aktualizowanie lokalnej bazy danych

$ locate bin/ls
locate: /var/spool/locate/locatedb: No such file or directory
$ su -
Password:
# updatedb

Generowanie tej bazy może zając sporo czasu. Jeżeli masz głośny dysk twardy, na pewno trochę pochałasuje podczas indeksowania całego systemu plików ;]

slocate

Na wielu dystrybucjach polecenie locate zostało zastąpione przez slocate. Zazwyczaj istnieje dowiązanie symboliczne do locate, więc nie musimy pamiętać które z tych poleceń mamy u siebie. slocate oznacza bezpieczną ("secure") wersję locate. Przechowuje ono w bazie także informacje dotyczące uprawnień do danych plików, więc użytkownicy nie będą mogli szperać po katalogach, do których normalnie nie mają dostępu. slocate używa się w identyczny sposób jak locate, aczkolwiek wyniki działania mogą się różnić w zależności od użytkownika który je uruchomił.

4.  Kontrolowanie procesów

Uruchamiamy xeyes

Aby nauczyć się czegoś o kontroli procesów, musimy mieć jakiś obiekt eksperymentów. Posłuży nam do tego zabawka, którą uruchamiamy z poziomu X-Window.

Listing 4.1: Uruchamiamy proces

$ xeyes -center red

Zauważyliśmy już pewnie parę czerwonych oczu wpatrujących się w kursor naszej myszki. Widzimy też, że w oknie terminala nie pojawił się nowy znak zachęty.

Zatrzymywanie procesu

Aby odzyskać możliwość wpisywania poleceń, możemy nacisnąć kombinacje klawiszy Ctrl-C (^C).

Pojawi się znak zachęty w konsoli, ale okienko xeyes zniknie. Prawde mówiąc, właśnie zabiliśmy proces. Zamiast Ctrl-C mogliśmy użyć delikatniejszego "środka perswazji" jakim jest Ctrl-Z, które tylko zatrzyma proces:

Listing 4.2: Zatrzymywanie procesu

$ xeyes -center red
Control-Z
[1]+  Stopped                 xeyes -center red
$

Tym razem wyświetli się nowy znak zachęty, a także okienko xeyes. Nie trudno zauważyć, że oczy się nie ruszają. Jeżeli zakryjemy je jakimś innym oknem, a następnie odsuniemy to okno zauważymy, że oczy w ogóle nie są odświeżane. Proces nie robi nic, jest "zatrzymany".

fg i bg

Żeby "odstopować" proces możemy przywrócić go na pierwszy plan za pomocą wbudowanej komendy basha fg:

Listing 4.3: Używamy fg

$ fg
(Przetestujmy to, a następnie zatrzymajmy ponownie proces)
Control-Z
[1]+  Stopped                 xeyes -center red
$

Teraz, za pomocą bg pozwolimy procesowi wykonywać się w tle:

Listing 4.4: Używamy bg

$ bg
[1]+ xeyes -center red &
$

Świetnie! Mamy proces działający w tle oraz nowy znak zachęty.

Używanie "&"

Jeżeli chcielibyśmy uruchomić xeyes tak aby od razu wykonywały się w tle (nie dopiero po użyciu Ctrl-Z i bg), moglibyśmy po prostu dodać "&" do polecenia xeyes:

Listing 4.5: Używamy & aby uruchamiać procesy w tle

$ xeyes -center blue &
[2] 16224

Kilka działających w tle procesów

Mamy teraz uruchomione w tle zarówno czerwone jak i niebieskie xeyes. Możemy wypisać listę tych procesów za pomocą polecenia jobs:

Listing 4.6: Używamy jobs

$ jobs -l
[1]- 16217 Running                 xeyes -center red &
[2]+ 16224 Running                 xeyes -center blue &

Liczby w lewej kolumnie są numerami procesów które zostały im przypisane przez powłokę bash, w momencie ich uruchomienia. Proces 2 jest oznaczony + (plusem) aby zaznaczyć, że jest to "aktualny proces", czyli ten który zostanie przywrócony kiedy wpiszemy fg. Możemy przekazać do fg numer procesu który chcemy przywrócić - np. fg 1 przywróci czerwone xeyes. W następnej kolumnie widzimy id procesu, nazywany skrótowo pid, który został tu wyświetlony dzięki podaniu opcji -l do jobs. Przedostatnia kolumna informuje nas, że oba procesy są uruchomione ("Running"), a ostatnia - jakie polecenie uruchomiło dany proces.

Wprowadzenie do sygnałów

Aby zakończyć, zatrzymać lub przywrócić proces, Linux używa specjalnego typu komunikacji, zwanej "sygnałami". Wysyłając dany sygnał do procesu, możemy go zakończyć, zatrzymać, itd. To właśnie robimy naciskając kombinacje Ctrl-C, Ctrl-Z lub używając poleceń bg albo fg - każemy powłoce bash wysłać określony sygnał do danego procesu. Możemy je także wysyłać używając polecenia kill razem z danym numerem pid:

Listing 4.7: Używamy kill

$ kill -s SIGSTOP 16224
$ jobs -l
[1]- 16217 Running                 xeyes -center red &
[2]+ 16224 Stopped (signal)        xeyes -center blue

Jak widać kill niekoniecznie musi zabić proces (ang. "kill" = zabij), aczkolwiek może to zrobić. Za pomocą opcji "-s" możemy wysłać do procesu dowolny sygnał. Linux zabije proces, zatrzyma go lub będzie kontynuował jego wykonywanie, odpowiednio dla sygnałów SIGINT, SIGSTOP, SIGCONT. Sygnałów które możemy wysyłać jest oczywiście więcej. Niektóre z nich mogą być interpretowane od strony samej aplikacji która jest ich adresatem. Więcej informacji na temat tego, jakie sygnały rozpoznaje dany proces, znajduje się na jego stronie w podręczniku systemowym w sekcji SYGNAŁY ("SIGNALS").

SIGTERM i SIGINT

Jeżeli chcemy zakończyć proces, mamy kilka możliwości. Standardowo, kill wysyła sygnał SIGTERM, który nie jest tym samym co SIGINT wysyłany przez Ctrl-C, ale zazwyczaj ma ten sam rezultat:

Listing 4.8: Używamy kill aby zakończyć proces

$ kill 16217
$ jobs -l
[1]- 16217 Terminated              xeyes -center red
[2]+ 16224 Stopped (signal)        xeyes -center blue

Duży kill

Proces może zignorować zarówno SIGTERM jak i SIGINT. Może to być jego "świadomy" wybór, a może po prostu się zaciął. W takim wypadku musimy mieć możliwość użycia czegoś potężniejszego - sygnału SIGKILL. Proces nie może go zignorować:

Listing 4.9: Unicestwiamy proces używając SIGKILL

$ kill 16224
$ jobs -l
[2]+ 16224 Stopped (signal)        xeyes -center blue
$ kill -s SIGKILL
$ jobs -l
[2]+ 16224 Interrupt               xeyes -center blue

nohup

Terminal w którym uruchamiamy dany proces, jest jego "terminalem kontrolnym". Niektóre powłoki (nie bash), wyślą do kontrolowanych przez siebie procesów sygnał SIGHUP, w momencie naszego wylogowania się, zmuszając je do zakończenia działania. Aby je przed tym uchronić możemy użyć nohup podczas ich uruchamiania:

Listing 4.10: nohup w akcji

$ nohup make &
[1] 15632
$ exit

Listujemy procesy używając ps

Poprzednio używaliśmy jobs aby wyświetlić procesy uruchomione z poziomu danej sesji basha. Aby zobaczyć wszystkie procesy działające w systemie używamy ps z opcjami a i x:

Listing 4.11: ps z opcjami ax

$ ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        S      0:04 init [3]
    2 ?        SW     0:11 [keventd]
    3 ?        SWN    0:13 [ksoftirqd_CPU0]
    4 ?        SW     2:33 [kswapd]
    5 ?        SW     0:00 [bdflush]

Przykład zawiera tylko kilka pierwszych linii ponieważ cała lista jest zwykle bardzo długa. Mimo iż jest ona obrazem systemu z chwili kiedy zostało wykonane polecenie ls, dostarcza nam wielu użytecznych informacji. Jeżeli nie dodamy opcji ax, zobaczymy tylko te procesy których jesteśmy właścicielami i które mają kontrolujący je terminal. Polecenie ps x pokaże wszystkie nasze procesy, nawet te które nie posiadają terminala. Jeżeli użyjemy ps a dostaniemy listę procesów wszystkich użytkowników które są podłączone do jakiegokolwiek terminala.

Oglądamy las i drzewa

Możemy też wyświetlić różne informacje dla każdego procesu. Opcja --forest ("las") pozwala nam obejrzeć hierarchię procesów, która pozwoli nam zrozumieć zależności między poszczególnymi procesami w systemie. Kiedy jeden proces uruchamia kolejny, ten kolejny proces jest nazywany procesem potomnym ("child"). W wydruku ps --forest procesy macierzyste znajdują się po lewej stronie, a procesy potomne po prawej:

Listing 4.12: Używamy forest

$ ps x --forest
  PID TTY      STAT   TIME COMMAND
  927 pts/1    S      0:00 bash
 6690 pts/1    S      0:00  \_ bash
26909 pts/1    R      0:00      \_ ps x --forest
19930 pts/4    S      0:01 bash
25740 pts/4    S      0:04  \_ vi processes.txt

Opcje "u" oraz "l"

Aby otrzymać szczegółowe informacje dotyczące każdego procesu, możemy połączyć opcje u i l z dowolną kombinacją a oraz x:

Listing 4.13: Opcja au

$ ps au
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
agriffis   403  0.0  0.0  2484   72 tty1     S     2001   0:00 -bash
chouser    404  0.0  0.0  2508   92 tty2     S     2001   0:00 -bash
root       408  0.0  0.0  1308  248 tty6     S     2001   0:00 /sbin/agetty 3
agriffis   434  0.0  0.0  1008    4 tty1     S     2001   0:00 /bin/sh /usr/X
chouser    927  0.0  0.0  2540   96 pts/1    S     2001   0:00 bash

Listing 4.14: Opcja al

$ ps al
  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
100  1001   403     1   9   0  2484   72 wait4  S    tty1       0:00 -bash
100  1000   404     1   9   0  2508   92 wait4  S    tty2       0:00 -bash
000     0   408     1   9   0  1308  248 read_c S    tty6       0:00 /sbin/ag
000  1001   434   403   9   0  1008    4 wait4  S    tty1       0:00 /bin/sh
000  1000   927   652   9   0  2540   96 wait4  S    pts/1      0:00 bash

Używamy top

Jeżeli dosyć często uruchamiamy ps aby obserwować zmiany wśród procesów, jesteśmy gotowi aby poznać polecenie top, które wyświetla bez przerwy aktualizowaną listę procesów, zawierającą dużo użytecznych, ogólnych informacji o samym systemie:

Listing 4.15: top

$ top
 10:02pm  up 19 days,  6:24,  8 users,  load average: 0.04, 0.05, 0.00
75 processes: 74 sleeping, 1 running, 0 zombie, 0 stopped
CPU states:  1.3% user,  2.5% system,  0.0% nice, 96.0% idle
Mem:   256020K av,  226580K used,   29440K free,       0K shrd,    3804K buff
Swap:  136544K av,   80256K used,   56288K free                  101760K cached

  PID USER     PRI  NI  SIZE  RSS SHARE STAT  LIB %CPU %MEM   TIME COMMAND
  628 root      16   0  213M  31M  2304 S       0  1.9 12.5  91:43 X
26934 chouser   17   0  1272 1272  1076 R       0  1.1  0.4   0:00 top
  652 chouser   11   0 12016 8840  1604 S       0  0.5  3.4   3:52 gnome-termin
  641 chouser    9   0  2936 2808  1416 S       0  0.1  1.0   2:13 sawfish

nice

Każdy proces ma swój priorytet, który pozwala systemowi Linux przydzielać mu dopowiednią część czasu procesora. Możemy ustawiać ten priorytet dla danego procesu uruchamiając go razem z poleceniem nice:

Listing 4.16: Ustawiamy priorytet procesu przy jego uruchamianiu

$ nice -n 10 oggenc /tmp/song.wav

Ponieważ ustawienie to nazywa się nice (ang. "miły", "delikatny"), łatwo nam będzie zapamiętać, że im wyższa wartość, tym proces jest "milszy" dla pozostałych procesów, pozwalając im na priorytetowy dostęp do procesora. Standardowo, proces zostaje uruchomiony z priorytetem 0, więc zmiana na 10 oznacza, że oggenc chętnie podzieli się czasem procesora z innymi procesami. Ogólnie rzecz biorąc oznacza to, że oggenc pozwoli innym programom wykonywać się z ich normalną prędkością, bez względu na to jak oggenc potrafi być zasobożerny. Poziom nice jest wyświetlany w kolumnie NI wydruku poleceń ps i top.

renice

Polecenia nice możemy używać jedynie podczas startowania procesu. Jeżeli chcemy zmienić poziom nice dla procesu który jest juz uruchomiony, musimy użyć polecenia renice:

Listing 4.17: Używamy renice

$ ps l 641
  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000  1000   641     1   9   0  5876 2808 do_sel S    ?          2:14 sawfish
$ renice 10 641
641: old priority 0, new priority 10
$ ps l 641
  F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  STAT TTY        TIME COMMAND
000  1000   641     1   9  10  5876 2808 do_sel S    ?          2:14 sawfish

5.  Przetwarzanie tekstu

Jeszcze raz o przekierowywaniu

Opisywaliśmy już wcześniej jak używać operatora > do przekierowywania danych wyjściowych programu do pliku. Przypomnijmy ten przykład:

Listing 5.1: Używamy operatora >

$ echo "pierwszy plik" > skopiujmnie

Oprócz przekierowywania danych wyjściowych do pliku, możemy także wykorzystać potężne narzędzie dostarczane przez powłokę systemową - potoki. Używając potoków, możemy przekierować dane wyjściowe jednego programu na wejście innego. Rozważmy następujący przykład:

Listing 5.2: Wprowadzenie do potoków

$ echo "hej tam!" | wc
      1       2       9

Znak | używamy, aby połączyć wyjście "lewego" polecenia, z wejściem polecenia "prawego". W powyższym przykładzie, polecenie echo drukuje ciąg "hej tam!" razem ze znakiem przejścia do następnego wiersza i to normalnie zobaczylibyśmy na ekranie, ale potok przekierowuje te dane, na wejście polecenia wc, które pokazuje ilość linii, słów oraz znaków w ciągu wejściowym.

Przykład potoku

Oto kolejny prosty przykład:

Listing 5.3: potoki w akcji

$ ls -s | sort -n

W tym wypadku, ls -s normalnie wydrukowało by listę plików znajdujących się w bieżącym katalogu, poprzedzając nazwę każdego pliku, jego rozmiarem. Zamiast tego, przekierowaliśmy wyjście do polecenia sort -n, które posortuje dane numerycznie. Jest to bardzo użyteczny sposób na znajdowanie dużych plików w naszych katalogach domowych!

Następne przykłady będą bardziej skomplikowane, ale demonstrują one potęge którą możemy ujarzmić używając potoków. Użyjemy paru poleceń które nie zostały jeszcze omówione, ale nie powinno nam to przeszkadzać. Skoncentrujmy się lepiej na zasadzie działania potoków, aby być w stanie je wykorzystywać w codziennej pracy z Linuksem.

Potok dekompresji

Normalnie aby zdekompresować i rozpakować plik, użylibyśmy następujących poleceń:

Listing 5.4: Dekompresja i rozpakowywanie pliku

$ bzip2 -d linux-2.4.16.tar.bz2
$ tar xvf linux-2.4.16.tar

To rozwiązanie ma swoją złą stronę - wymaga utworzenia na dysku zdekompresowanego pliku pośredniego. Ponieważ tar ma możliwość odczytu danych wejściowych (zamiast z pliku), możemy otrzymać taki sam wynik używając potoków:

Listing 5.5: Dekompresja i rozpakowywanie przy użyciu potoków

$ bzip2 -dc linux-2.4.16.tar.bz2 | tar xvf -

Świetnie! Nasz plik został zdekompresowany i rozpakowany, bez konieczności tworzenia pliku tymczasowego na dysku.

"Dłuższy" potok

Oto kolejny przykład:

Listing 5.6: Dłuższy potok

$ cat mojplik.txt | sort | uniq | wc -l

Używamy cat aby przekazać zwartość pliku mojplik.txt do polecenia sort, które sortuje dane wejściowe w porządku alfabetycznym, a następnie wysyła je do polecenia uniq. uniq usuwa wszystkie powtarzające się linie (dane wejściowe muszą być posortowane), a następnie wysyła pozostałe, unikalne linie do polecenia wc -l. Spotkaliśmy się już z wc, ale bez żadnych opcji. Podając -l jako opcję, wc pokaże jedynie ilość linii podanych na wejściu, nie zobaczymy liczb określających ilość znaków i słów. Efektem tego potoku, będzie ilość unikalnych linii zawartych w podanym pliku tekstowym.

Stwórzmy teraz jakiś plik z dowolną zawartością i sprawdźmy jaki będzie rezultat wykonania naszego potoku.

Rozpoczynamy przygodę z przetwarzaniem tekstu

Teraz skupimy się na standardowych poleceniach Linuksa, służących do przetwarzania tekstu. Nie zostaną przytoczone przykłady dla wszystkich użytych poleceń. Aby uzyskać więcej informacji powinniśmy zajrzeć na strony podręcznika systemowego dla każdego z tych poleceń (pisząc np. man echo) i poeksperymentować z poszczególnymi opcjami. Główną zasadą działania tych programów, jest przetwarzanie tekstu i drukowanie wyników na ekran konsoli - nie modyfikują one plików z których pobierają dane. Po tym krótkim opisie poleceń przetwarzających tekst, zajmiemy się przekierowywaniem wejścia/wyjścia.

echo drukuje na konsolę, przekazane mu argumenty. Jeżeli użyjemy opcji -e bash będzie interpretował specjalne sekwencje znaków które poznaliśmy wcześniej. Na przykład echo -e "foo\nfoo" wypisze na konsoli foo, następnie przejdzie do nowej linii gdzie wydrukuje kolejne foo. Opcja -n spowoduje, że echo nie będzie kończyło swojego działania przechodząc do nowej linii.

cat wydrukuje zawartość podanego jako argument pliku, na ekran. Jest użyteczne jako pierwsze polecenie w potoku, np. cat foo.txt | blah.

sort wyświetli w porządku alfabetycznym zawartość pliku podanego jako argument. Oczywiście akceptuje także na wejściu, przekierowane dane wyjściowe innego polecenia. Szczegółowe informacje znajdują sie w manie.

uniq pobiera posortowaną wcześniej zawartość pliku bądź ciąg danych (poprzez potok) i usuwa z nich powtarzające się linie.

wc podaje ilość linii, słów oraz bajtów, dla danego pliku lub strumienia wejściowego (z potoku). man wc dostarczy nam wszystkich potrzebnych informacji dot. wyświetlania tych danych.

head drukuje pierwsze 10 linii pliku bądź strumienia. Możemy sprecyzować ilość drukowanych linii podając odpowiednią liczbę po opcji -n.

tail drukuje 10 ostatnich linii w pliku bądź strumieniu. Tak jak dla head możemy określić ilość linii za pomocą opcji -n.

tac działa jak cat, ale drukuje linie w odwrotnej kolejności - ostatnia linia jest drukowana jako pierwsza itd.

expand zamienia znaki tabulacji na spacje.

unexpand zamienia spacje na znaki tabulacji.

cut służy do wycinania z każdej linii, z pliku bądź strumienia wejściowego, pól ograniczonych przez dane znaki.

nl dodaje numer linii do każdej linii wejściowej. Użyteczne do wydruków.

pr używamy aby dzielić pliki na strony - użyteczne przy drukowaniu.

tr jest narzędziem służącym do tłumaczenia. Zastępujemy nim konkretne znaki ze strumienia wejściowego, na inne które pojawią się na wyjściu.

sed jest potężnym edytorem zorientowanym strumieniowo. Możemy dowiedzieć się o nim więcej z następujących artykułów IBM developerWorks:

Jeżeli planujemy podejść do egzaminu LPI, powinniśmy przeczytać przynajmniej dwie pierwsze części tej serii.

awk jest bardzo użytecznym, zorientowanym liniowo językiem, służącym do przetwearzania tekstu. Aby dowiedzieć się więcej na jego temat powinniśmy przeczytać następujące artykuły IBM developerWorks:

od zostało stworzone, aby przekształcać dane wejściowe na format ósemkowego lub szesnastkowego "zrzutu".

split jest poleceniem, używanym do dzielenia dużych plików, na kilka mniejszych, wygodniejszych kawałków.

fmt zawinie wiersze które wykraczają poza margines. Ponieważ opcja ta jest już wbudowana w większość edytorów, polecenie jest mało użyteczne, aczkolwiek warto je znać.

paste pobiera dane z dwóch lub więcej plików i drukuje ich zawartość umieszczając obok siebie kolejne linie. Może się przydać do drukowania tabel lub kolumn tekstu.

join używa pól (zazwyczaj pierwszego) do porównywania plików i drukuje obok siebie te linie, w których pola się zgadzają.

tee drukuje dane wejściowe zarówno na ekran jak i do pliku. Jest ono bardzo użyteczne gdy chcemy coś zalogować, jednocześnie śledząc wyniki działaniana programu na ekranie.

Koniec wprowadzenia! Przekierowywanie

Podobnie jak > w linii poleceń basha, możemy użyć < aby przekierować plik do danego polecenia. Dla wielu poleceń możemy po prostu sprecyzować nazwę pliku w linii poleceń, aczkolwiek niektóre polecenia działają pobierając dane tylko ze standardowego wejścia.

Bash i inne powłoki wspierają koncepcję "herefile". Pozwala to nam podać dane do polecenia, w liniach następujących po wywaołaniu polecenia, zakończonych określoną sentencją. Najprościej pokazać to na przykładzie:

Listing 5.7: Przekierowywanie w akcji

$ sort <<KONIEC
jablko
zurawina
banan
KONIEC
banan
jablko
zurawina

W powyższym przykładzie, wpisaliśmy słowa jabłko, żurawina i banan, oraz "KONIEC" aby zaznaczyć koniec danych wejściowych. Program sort zwrócił dane posortowane alfabetycznie.

Używamy >>

Moglibyśmy się spodziewać, że >> będzie działało analogicznie do <<, ale tak nie jest. Znaczy to po prostu aby dopisać dane wyjściowe do pliku, w odróżnieniu od > które nadpisze ten plik:

Listing 5.8: Przekierowywanie do pliku

$ echo Hej > mojplik
$ echo tam. > mojplik
$ cat mojplik
tam.

Ups! Gdzie nasze "Hej"? Mieliśmy na myśli raczej coś takiego:

Listing 5.9: Dopisywanie do pliku

$ echo Hej > mojplik
$ echo tam. >> mojplik
$ cat mojplik
Hej
tam.

Dużo lepiej!

6.  Moduły jądra

Poznajemy "uname"

Polecenie uname dostarcza nam wielu interesujących informacji o systemie. Oto co wyświetla autorowi tego artykułu polecenie uname -a, które każe uname pokazać wszystkie informacje naraz:

Listing 6.1: uname -a

$ uname -a
Linux inventor 2.4.20-gaming-r1 #1 Fri Apr 11 18:33:35 MDT 2003 i686 AMD Athlon(tm) XP 2100+ AuthenticAMD GNU/Linux

Wiecej o uname

Teraz przyjrzyjmy się informacjom dostarczanym przez uname

Listing 6.2: informacje uname

opcja                           arg     przykład
nazwa jądra                     -s      "Linux"
nazwa hosta                     -n      "inventor"
numer wydania jądra             -r      "2.4.20-gaming-r1"
wersja jądra                    -v      "#1 Fri Apr 11 18:33:35 MDT 2003"
maszyna                         -m      "i686"
procesor                        -p      "AMD Athlon(tm) XP 2100+"
platforma sprzętowa             -i      "AuthenticAMD"
system operacyjny              -o      "GNU/Linux"

Interesujące! A co pokaże nasze uname -a ?

Numer wydania jądra

Oto magiczna sztuczka. Najpierw, napiszmy uname -r aby polecenie uname wypisało numer wydania jądra Linuksa, którego aktualnie używamy.

Teraz, zajrzyjmy do katalogu /lib/modules i Uwaga! Oto jest katalog o identycznej nazwie! No dobra, może nie była to jakaś super sztuczka, za to chwila jest odpowiednia aby dowiedzieć się o znaczeniu katalogów w /lib/modules oraz wyjaśnić czym są moduły jądra.

Jądro

Jądro Linuksa jest sercem tego, co powszechnie określane jest mianem "Linux". Jest to kod, który ma bezpośredni dostęp do sprzętu, dostarczając warstwę abstrakcji pozwalającej na działanie starych programów. Dzięki jądru, nasz edytor tekstowy nie musi się martwić o to czy dane są zapisywane na dysk SCSI czy IDE lub nawet na RAM-disk. On po prostu zapisuje do systemu plików, a jądro zajmuje się resztą.

Wprowadzenie do modułów jądra

Czym są właściwie moduły jądra? Cóż, są one częściami jądra, przechowywanymi na dysku w specjalnym formacie. Na nasze życzenie, mogą zostać załadowane do działającego jądra, umożliwiając mu dostarczanie dodatkowych opcji.

Ponieważ moduły jądra są ładowane na żądanie, możemy zwiększyć funkcjonalność naszego jądra o opcje których nie chcemy mieć włączonych standardowo, a które przydadzą się od czasu do czasu aby obsłużyć jakiś dziwny system plików, lub kawałek sprzętu którego rzadko używamy.

Moduły jądra "w pigułce"

Moduły jądra pozwalają na żądanie powiększać możliwości działającego jądra. Bez modułów, musielibyśmy skompilować nowe jądro i zrestartować komputer, aby był on w stanie obsłużyć coś nowego.

lsmod

Aby zobaczyć które moduły są obecnie załadowane w naszym systemie, używamy polecenia lsmod:

Listing 6.3: Używamy lsmod

# lsmod
Module                  Size  Used by    Tainted: PF
vmnet                  20520   5
vmmon                  22484  11
nvidia               1547648  10
mousedev                3860   2
hid                    16772   0  (unused)
usbmouse                1848   0  (unused)
input                   3136   0  [mousedev hid usbmouse]
usb-ohci               15976   0  (unused)
ehci-hcd               13288   0  (unused)
emu10k1                64264   2
ac97_codec              9000   0  [emu10k1]
sound                  51508   0  [emu10k1]
usbcore                55168   1  [hid usbmouse usb-ohci ehci-hcd]

Lista modułów

Jak widać, ten system ma załadowanych kilka modułów. vmnet i vmmon zapewniają funkcjonalność dla programu VMWare, który pozwala na uruchomienie wirtualnego komputera na pulpicie. Moduł "nvidia" pochodzi od korporacji NVIDIA i umożliwia używanie wydajnego akceleratora graficznego pod Linuksem, kożystając z jego wielu ciekawych możliwości.

Następnie widzimy kilka modułów które są używane do obsługi urządzeń USB: "mousedev", "hid", "usbmouse", "input", "usb-ohci", "ehci-hcd" i "usbcore". Konfiguracja jądra z obsługą USB w postaci modułów jest dobrym rozwiązaniem, ponieważ urządzenia USB są typu "plug and play" - możemy pójść do sklepu, kupić nowe urządzenie USB, podłączyć je do komputera i pozwolć aby system sam załadował wymagane moduły aby dane urządzenie działało. Jest to bardzo wygodne rozwiązanie.

moduły z zewnętrznych źródeł

Moduły "emu10k1", "ac97_codec" i "sound", zapewniają obsługę karty muzycznej SoundBlaster Audigy.

Musimy wiedzieć, że niektóre modułów jądra pochodzi właśnie z samych jego źródeł - np. wszystkie związane z USB moduły, są kompilowane ze źródeł jądra Linuksa. Są także moduły, takie jak nvidia, emu10k1 i VMWare, które pochodzą z innych źródeł. Pozwala nam to dostrzec kolejną zaletę modułów jądra - możliwe jest dostarczanie zewnętrznym firmom własnych modułów obsługujących ich sprzęt, które możemy załadować do jądra bez konieczności restartowania komputera.

depmod i przyjaciele

w katalogu /lib/modules/2.4.20-gaming-r1/ naszego przykładowego systemu, znajduje się kilka plików których nazwa zaczyna się od "modules.":

Listing 6.4: inne moduły

$ ls /lib/modules/2.4.20-gaming-r1/modules.*
/lib/modules/2.4.20-gaming-r1/modules.dep
/lib/modules/2.4.20-gaming-r1/modules.generic_string
/lib/modules/2.4.20-gaming-r1/modules.ieee1394map
/lib/modules/2.4.20-gaming-r1/modules.isapnpmap
/lib/modules/2.4.20-gaming-r1/modules.parportmap
/lib/modules/2.4.20-gaming-r1/modules.pcimap
/lib/modules/2.4.20-gaming-r1/modules.pnpbiosmap
/lib/modules/2.4.20-gaming-r1/modules.usbmap

Pliki te przechowują wiele informacji o zależnościach. Na przykład, są w nich zapisane informacje o zależnościach między modułami - niektóre moduły wymagają wcześniejszego załadowania innych modułów, zanim same będą mogły znaleźć się w jądrze.

Skąd się biorą moduły

Niektóre moduły jądra są zaprojektowane tak, aby działać z określonym sprzętem. Przykładem jest "emu10k1" który obsługuje kartę muzyczną SoundBlaster Audigy. Dla tego typu modułów, pliki te przechowują informacje, takie jak PCI ID itp. identyfikatory sprzętu który dany moduł potrafi obsługiwać. Te informacje mogą być użyte np. przez skrypty "hotplug" (którym przyjrzymy się później) do automatycznego wykrywania sprzętu i ładowania odpowiednich modułów do jądra.

Używamy depmod

Jeżeli kiedykolwiek zdarzyło się nam instalować nowy moduł, informacje o zależnościach mogą być nieaktualne. Aby je zaktualizować wystarczy użyć polecenia depmod -a. W efekcie program depmod przejrzy moduły znajdujące się w /lib/modules i odświerzy informacje o zależnościach. Program czerpie te informacje z poszczególnych modułów szukając w nich tzw. "symboli".

Wyszukiwanie modułów jądra

Jak wyglądają moduły jądra? dla jąder z serii 2.4, są one zazwyczaj każdym plikiem znajdującym się w /lib/modules zakończonym ".o". Aby zobaczyć wszystkie moduły w /lib/modules, wpisujemy następujące polecenie:

Listing 6.5: moduły jądra w /lib/modules

# find /lib/modules -name '*.o'
/lib/modules/2.4.20-gaming-r1/misc/vmmon.o
/lib/modules/2.4.20-gaming-r1/misc/vmnet.o
/lib/modules/2.4.20-gaming-r1/video/nvidia.o
/lib/modules/2.4.20-gaming-r1/kernel/fs/fat/fat.o
/lib/modules/2.4.20-gaming-r1/kernel/fs/vfat/vfat.o
/lib/modules/2.4.20-gaming-r1/kernel/fs/minix/minix.o
[ucięte aby zachować przejrzystość]

insmod kontra modprobe

W jaki sposób są ładowane moduły do jądra? Można to zrobić za pomocą polecenia insmod podając pełną scieżkę do modułu który chcemy załadować:

Listing 6.6: Używamy insmod

# insmod /lib/modules/2.4.20-gaming-r1/kernel/fs/fat/fat.o
# lsmod | grep fat
fat                    29272   0  (unused)

Zazwyczaj jednak, wygodniej jest używać polecenia modprobe, ponieważ nie musimy się troszczyć o zależności, a także zwalnia nas ono z obowiązku podawania dokładnej ścieżki do modułu oraz końcówki ".o".

rmmod oraz modprobe w akcji

Spróbujmy usunąć moduł "fat.o" za pomocą rmmod, a następnie załadować go, używając modprobe:

Listing 6.7: rmmod oraz modprobe w akcji

# rmmod fat
# lsmod | grep fat
# modprobe fat
# lsmod | grep fat
fat                    29272   0  (unused)

Jak widzimy, polecenie rmmod działa podobnie do modprobe, ale ma przeciwny skutek - usuwa z jądra żądany moduł.

Nasz przyjaciel modinfo i modules.conf

Używając polecenia modinfo możemy uzyskać ciekawe informacje na temat naszych ulubionych modułów:

Listing 6.8: Używamy modinfo

# modinfo fat
filename:    /lib/modules/2.4.20-gaming-r1/kernel/fs/fat/fat.o
description: <none>
author:      <none>
license:     "GPL"

Powinniśmy także pamiętać o pliku /etc/modules.conf, który zawiera informacje konfiguracyjne modprobe. Pozwala on nam, zwiększyć funkcjonalność modprobe przekazując mu informacje aby załadował jedne moduły przed/po drugich, uruchamiał skrypty przed/po załadowaniu modułów, itd.

pułapki w modules.conf

Składnia i funkcje modules.conf są dosyć skomplikowane i nie będziemy się nimi zajmować (mnóstwo informacji znajdziemy w man modules.conf), ale jest parę rzeczy dot. tego pliku, o których powinniśmy wiedzieć.

Po pierwsze, wiele dystrybucji generuje ten plik automatycznie ze sporej ilości plików z innego katalogu - np. /etc/modules.d/. Dla przykładu, dystrybucja Gentoo Linux posiada katalog /etc/modules.d/, i uruchomienie polecenia update-modules stworzy nowy plik /etc/modules.conf na podstawie plików zawartych w /etc/modules.d/. Tak więc jeżeli używamy Gentoo, zróbmy co trzeba z plikami w /etc/modules.d/ aby następnie wydać polecenie update-modules. Jeżeli używamy Debiana, procedura jest podobna, przy czym katalog nazywa się /etc/modutils/.

7.  Podsumowanie i zasoby informacji

Podsumowanie

Gratulacje! Dotarliście do końca artykułu dotyczącego podstaw administracji systemem Linux! Mamy nadzieję, że pomógł on wam uporządkować podstawową wiedzę na temat Linuksa. Zachęcamy do przeczytania kolejnego artykułu z tej serii, poruszającego tematykę bardziej zaawansowanej administracji systemem. Zajmiemy się w nim prawami dostępu oraz modelem dostępu, zarządzaniem kontami użytkowników, tworzeniem i montowaniem systemów plików oraz wieloma innymi zagadnieniami. Nie zapominajmy o tym, że kontynuując lekturę tej serii artykułów, będziemy niedługo gotowi do zdobycia certyfikatu LPIC pierwszego poziomu, Linuksowego Instytutu Profesjonalistów (LPI).

Zasoby informacji

Skoro mówimy już o certyfikacie LPIC i jeżeli jesteśmy nim zainteresowani, powinniśmy przejrzeć informacje zawarte w poniższych źródłach, starannie dobranych aby umożliwić poszerzenie informacji dot. tematów poruszanych w tym artykule:

Jest wiele dobrych zasobów informacji dotyczących wyrażeń regularnych. Oto kilka z tych, które znaleźliśmy:

Powinniśmy też przeczytać dokument o standardzie hierarchii systemu plików na http://www.pathname.com/fhs/.

W serii artykułów "Bash w przykładach", Dowiemy się jak używać konstrukcji programistycznych basha do pisania własnych skryptów. Seria ta (a dokładniej jej pierwsza i druga część) przygotuje nas do pierwszego poziomu egzaminu LPIC.

Więcej na temat edytora sed dowiemy się z pozostałych artykułów IBM developerWorks. Jeżeli planujemy podejść do egzaminu LPI, powinniśmy przeczytać przynajmniej dwa pierwsze artykuły z tej serii.

Aby dowiedzieć się więcej o awk, powinniśmy przeczytać artykuły IBM developerWorks dotyczące tego tematu.

Polecamy także lekturę Technical FAQ for Linux users - 50-stronicowej listy najczęściej zadawanych pytań dotyczących Linuksa, wraz z obszernymi odpowiedziami. FAQ jset w formacie PDF (Acrobat). Jeżeli jesteśmy początkującymi bądź średnio zaawansowanymi użytkownikami Linuksa, powinniśmy poświęcić trochę czasu na lekturę tego FAQ.

Jeżeli nie przywykliśmy jeszcze do edytora vi, powinniśmy przeczytać artykuł Nauka vi metodą "ściągawki". Jest on szybkim wprowadzeniem do tego potężnego edytora. Powinniśmy poważnie się zastanowić nad lekturą tego artykułu jeżeli nie wiemy jak używać vi.



Drukuj

Zaktualizowano 20 czerwca 2007

Podsumowanie: W tym artykule nauczymy się, jak używać wyrażeń regularnych do znajdowania ciągów znaków w plikach, jak znaleźć dany plik w systemie, a także jak sprawować pełną kontrolę nad procesami Linuksa. Przejdziemy również przyspieszony kurs dotyczący potoków, ich przekierowywania oraz przetwarzania tekstu. Po przeczytaniu tego artykułu będziemy mieli solidne podstawy w administrowaniu Linuksem i tym samym będziemy gotowi do nauki rzeczy bardziej zaawansowanych, o których jest mowa w kolejnym artykule z tej serii.

Daniel Robbins
Autor

Chris Houser
Autor

Aron Griffis
Autor

Łukasz Rysiak
Tłumacz

Donate to support our development efforts.

Support OSL
Gentoo Centric Hosting: vr.org
Tek Alchemy
SevenL.net
Global Netoptex Inc.
Bytemark
Online Kredit Index
Copyright 2001-2009 Gentoo Foundation, Inc. Questions, Comments? Contact us.