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