Polecenie WC,Sort,Tr,Grep,Egrep,Find.
Polecenie SORT
Sortowanie jest jednym z ważniejszych elementów programowania. Znajomość różnych algorytmów i technik sortowania to ważna część wiedzy programisty.
Tutaj jednak zajmiemy się czymś znacznie prostszym: wykorzystaniem unixowego polecenia sort do porządkowania jednego lub więcej plików, wiersz po wierszu, wedle ustalonych przez nas reguł. A przy okazji rozejrzymy się po środowisku w jakim pracujemy.
Wielu użytkowników kończy swoją znajomość polecenia sort na poleceniach typu:
$ sort some_file.txt
Domyślne zachowanie tego polecenia dla wielu prostych zastosowań będzie wystarczające - wyświetli w terminalu posortowane wiersze wskazanego pliku. Przyjrzymy się jednak działaniu tego polecenia nieco dokładniej. Można oczywiście przestudiować manual (polecenie man sort) ale łatwiej jest poznać specyfikę niektórych opcji i możliwości na przykładach.
Stwórzmy (polecenie touch) plik literki.txt zawierający po jednej literze w wierszu. Polecenie cat pozwoli nam wyświetlić jego zawartość (w tym i pozostałych przykładach znak dolara ($) zastępuje całe zgłoszenie systemowe (ang.: Prompt):
$ cat literki.txt
b
D
c
A
C
B
d
a
Podstawowe użycie polecenia sort widzimy poniżej:
$ sort literki.txt
a
A
b
B
c
C
d
D
a gdybyśmy chcieli posortować w odwrotnej kolejności:
sort -r letters.txt
D
d
C
c
B
b
A
a
W zasadzie wszystko dobrze, ale trochę dziwnie zachowuje się kolejność małych i dużych liter. W manualu do polecenia sort czytamy, że opcja: -f (lub --ignore-case) powoduje nierozróżnianie małych i dużych liter przy porównywaniu. Powinno to być zachowanie domyślne, ale sprawdźmy:
a
A
b
B
c
C
d
D
$ sort -rf literki.txt
D
d
C
c
B
b
A
a
Oszustwo! Widać gołym okiem, że nierozróżnianie małych i dużych liter nie jest prawdą. Co gorsza polecenie sort zachowuje się niestabilnie, to znaczy zmienia kolejność wierszy również tam, gdzie powinno traktować je jako "równe" z punktu widzenia reguł sortowania. Dopiero dodanie opcji -s (--stable) zmienia sytuację:
$ sort -rfs literki.txt
D
d
c
C
b
B
A
a
$ sort -fs literki.txt
A
a
b
B
c
C
D
d
Dlaczego tak jest? Ano, po szczegółowej lekturze opisu działania polecenia sort można się dowiedzieć, że jeśli sortowane wiersze nie różnią się z punktu widzenia przyjętych reguł to jako ostateczne kryterium stosowane jest jeszcze porównywanie kodów znaków! Dopiero opcja -s wyłącza to ostatnie porównywanie.
Zmodyfikujmy plik literki.txt, tak by otrzymać:
$ cat literki.txt
b
D
c
ą
A
C
B
d
ć
a
Kody "polskich literek" 'ą' oraz 'ć' powinny umieszczać je daleko od 'a' czy 'c' . Sprawdźmy:
$ sort -f literki.txt
a
A
ą
b
B
c
C
ć
d
D
$ sort -fs literki.txt
A
a
ą
b
B
c
C
ć
D
d
Nadal coś nie tak! Duże i małe litery reagują na opcję -s (to znaczy duże i małe te same litery występuja teraz w takiej samej kolejności jak w pliku nieposortowanym) ale system skądś wie, że 'ą' jest w polskim alfabecie przed 'b' i kody najwyraźniej nie mają tu nic do rzeczy.
Jak przeczytamy manual polecenia sort do samego końca to znajdziemy jeszcze ostrzeżenie:
-
*** WARNING *** The locale specified by the environment affects sort
order. Set LC_ALL=C to get the traditional sort order that uses native
byte values.
Cóż to oznacza? Sprawdźmy ustawienia językowe:
$ locale
LANG=pl_PL
LC_CTYPE="pl_PL"
LC_NUMERIC="pl_PL"
LC_TIME="pl_PL"
LC_COLLATE="pl_PL"
LC_MONETARY="pl_PL"
LC_MESSAGES="pl_PL"
LC_PAPER="pl_PL"
LC_NAME="pl_PL"
LC_ADDRESS="pl_PL"
LC_TELEPHONE="pl_PL"
LC_MEASUREMENT="pl_PL"
LC_IDENTIFICATION="pl_PL"
LC_ALL=pl_PL
Widać, że system wie, iż posługujemy się językiem polskim i stąd jego "nadinteligencja" przy sortowaniu. Ale rada zawarta w powyższym ostrzeżeniu nie jest najlepsza - ustawienieLC_ALL="C" spowoduje przestawienie całego naszego środowiska na język angielski i siedmiobitowy kod ASCII. Polecenie man locale wyjaśnia, do czego służą poszczególne zmienne oraz, ze ustawienie zmiennej LC_ALL ma najwyższy priorytet. O kolejności sortowania decyduje ustawienie zmiennej LC_COLLATE. Aby jednak zadziałała musimy usunąć ustawienie zmiennej LC_ALL. Spróbujmy:
$ LC_ALL=
$ locale
LANG=pl_PL
LC_CTYPE="pl_PL"
LC_NUMERIC="pl_PL"
LC_TIME="pl_PL"
LC_COLLATE="pl_PL"
LC_MONETARY="pl_PL"
LC_MESSAGES="pl_PL"
LC_PAPER="pl_PL"
LC_NAME="pl_PL"
LC_ADDRESS="pl_PL"
LC_TELEPHONE="pl_PL"
LC_MEASUREMENT="pl_PL"
LC_IDENTIFICATION="pl_PL"
LC_ALL= <---------------------
$ export LC_COLLATE=C
$ locale
LANG=pl_PL
LC_CTYPE="pl_PL"
LC_NUMERIC="pl_PL"
LC_TIME="pl_PL"
LC_COLLATE=C <----------------------
LC_MONETARY="pl_PL"
LC_MESSAGES="pl_PL"
LC_PAPER="pl_PL"
LC_NAME="pl_PL"
LC_ADDRESS="pl_PL"
LC_TELEPHONE="pl_PL"
LC_MEASUREMENT="pl_PL"
LC_IDENTIFICATION="pl_PL"
LC_ALL=
$ sort literki.txt
A
B
C
D
a
b
c
d
ą
ć
$ sort -f literki.txt
A
a
B
b
C
c
D
d
ą
ć
Uff. Umiemy sortować litery. A co z liczbami? Stwórzmy plik numerki.txt:
$ cat numerki.txt
5
4
12
1
3
56
i spróbujmy posortować jego wiersze:
$ sort numerki.txt
1
12
3
4
5
56
Wiersze nie są uporządkowane numerycznie ale łatwo zgadnąć co się stało: polecenie sort nic nie wie o naszych zamiarach i nadal sortuje według kolejności leksykograficznej. Czyli najpierw według pierwszego znaku, potem drugiego (jeśli jest) itd. lekarstwem jest opcja -n:
$ sort -n numerki.txt
1
3
4
5
12
56
Działa! Ale zmodyfikujmy plik numerki.txt następująco:
$ cat numerki.txt
+5
-4
+0.12
-0.1
+0.3
-0.56
Wynik sortowania będzie zaskakujący:
$ sort -n numerki.txt
-4
+0.12
+0.3
+5
-0.1
-0.56
Jeśli ktoś sądzi, że użycie opcji -g zamiast -n pomoże (a tak sugeruje dokumentacja) to jest w błędzie:
$ sort -g numerki.txt
-4
+0.12
+0.3
-0.1
-0.56
+5
Jest jeszcze dziwniej!. Powodem znowu są ustawienia językowe! Przypomnijmy je sobie:
$ locale
LANG=pl_PL
LC_CTYPE="pl_PL"
LC_NUMERIC="pl_PL"
LC_TIME="pl_PL"
LC_COLLATE=C
LC_MONETARY="pl_PL"
LC_MESSAGES="pl_PL"
LC_PAPER="pl_PL"
LC_NAME="pl_PL"
LC_ADDRESS="pl_PL"
LC_TELEPHONE="pl_PL"
LC_MEASUREMENT="pl_PL"
LC_IDENTIFICATION="pl_PL"
LC_ALL=
Teraz wszystko psuje ustawienie: LC_NUMERIC="pl_PL". Czemu?!?!? Bo w języku polskim separatorem części dziesiętnej jest... przecinek. Polecenie sort posłusznie sortuje według kolejności liczbowej, pomijając te części wierszy, które nie są liczbami (czyli od kropki w prawo!). Tak więc najpierw mamy -4, potem cztery razy zero a potem +5. Dopiero zmiana naLC_NUMERIC=C daje oczekiwany wynik:
$ export LC_NUMERIC=C
$ sort -g numerki.txt
-4
-0.56
-0.1
+0.12
+0.3
+5
Sortowanie nieco bardziej zaawansowane
Wyprodukujmy plik tablica.txt (proponuje skopiować zawartość z przeglądarki zamiast wklepywania zawartości)), który wygląda tak:
$ cat tablica.txt
| 23 | 12 | 32 | 93 | 75 |
| 43 | 17 | 52 | 91 | 22 |
| 77 | 73 | 14 | 48 | 37 |
| 44 | 51 | 52 | 36 | 54 |
| 41 | 25 | 43 | 26 | 99 |
| 17 | 21 | 46 | 31 | 24 |
| 28 | 83 | 85 | 42 | 27 |
| 23 | 14 | 37 | 13 | 75 |
Dokumentacja polecenia sort mówi, że wiersze pliku wejściowego można sortować według poszczególnych pół lub grup pól. Służy do tego opcja: -k POS1[,POS2], gdzie POS1 to numer pierwszego pola branego pod uwagę a opcjonalny parametr POS2 to numer ostatniego pola. Zobaczmy jak to działa:
$ sort -n -k 4 tablica.txt
| 23 | 12 | 32 | 93 | 75 |
| 23 | 14 | 37 | 13 | 75 |
| 43 | 17 | 52 | 91 | 22 |
| 17 | 21 | 46 | 31 | 24 |
| 41 | 25 | 43 | 26 | 99 |
| 44 | 51 | 52 | 36 | 54 |
| 77 | 73 | 14 | 48 | 37 |
| 28 | 83 | 85 | 42 | 27 |
Cóż, wiersze są posortowane, ale według drugiej kolumny a nie czwartej! Czemu? Ano komputer to nie wróżka, i niby skąd ma wiedzieć co uważamy za "pole" w wierszu? Domyślnym separatorem pól są odstępy! To wyjaśnia powyższy wynik sortowania. Zaradzić temu można przy pomocy opcji -t (--field-separator=SEPARATOR) po której podajemy jaki znak ma być uważany za separator pól. Zatem polecenie:
$ sort -n -t'|' -k 4 tablica.txt
| 77 | 73 | 14 | 48 | 37 |
| 23 | 12 | 32 | 93 | 75 |
| 23 | 14 | 37 | 13 | 75 |
| 41 | 25 | 43 | 26 | 99 |
| 17 | 21 | 46 | 31 | 24 |
| 43 | 17 | 52 | 91 | 22 |
| 44 | 51 | 52 | 36 | 54 |
| 28 | 83 | 85 | 42 | 27 |
powinno posortować plik według czwartej kolumny. Jak widać posortowało według trzeciej! Dlaczego? Ano dlatego, że każdy wiersz zaczyna się od znaku zdefiniowanego jako separator, tak więc komputer "widzi" przed nim "puste pole" numer 1. Aby posortować według czwartej kolumny musimy w takim przypadku wydać polecenie:
$ sort -n -t'|' -k 5 tablica.txt
| 23 | 14 | 37 | 13 | 75 |
| 41 | 25 | 43 | 26 | 99 |
| 17 | 21 | 46 | 31 | 24 |
| 44 | 51 | 52 | 36 | 54 |
| 28 | 83 | 85 | 42 | 27 |
| 77 | 73 | 14 | 48 | 37 |
| 43 | 17 | 52 | 91 | 22 |
| 23 | 12 | 32 | 93 | 75 |
Poćwiczmy teraz nieco...
Polecenie $ ls -dla /etc/s* listuje wszystkie pliki i katalogi zawarte w /etc, których nazwy zaczynają się na literę 's' (na każdym komputerze wynik może się nieco różnić):
$ ls -dla /etc/s*
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sane.d
-rw-r--r-- 1 root root 666 sie 25 2009 /etc/scsi_id.config
-rw-r--r-- 1 root root 1287 lis 22 2008 /etc/securetty
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/security
-rw-r--r-- 1 root root 71449 sie 2 2008 /etc/sensors3.conf
-rw-r--r-- 1 root root 85602 lip 3 2008 /etc/sensors.conf
-rw-r--r-- 1 root root 2950 cze 29 2001 /etc/serial.conf
-rw-r--r-- 1 root root 18480 sie 28 2008 /etc/services
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sgml
-rw-r----- 1 root shadow 854 lut 24 2010 /etc/shadow
-rw------- 1 root root 854 gru 2 2009 /etc/shadow-
-rw-r--r-- 1 root root 155 mar 3 2010 /etc/shells
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/skel
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sound
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/ssh
drwxr-xr-x 4 root root 4096 paź 1 12:58 /etc/ssl
drwxr-xr-x 2 root root 4096 paź 1 12:57 /etc/ssmtp
-r--r----- 1 root root 481 gru 1 2009 /etc/sudoers
-rw-r--r-- 1 root root 2275 sty 11 2009 /etc/sysctl.conf
drwxr-xr-x 2 root root 4096 sty 11 2009 /etc/sysctl.d
Polecenie ls domyślnie sortuje wiersze alfabetycznie według nazw. Gdybyśmy chcieli posortować wynik tego polecenia według liczby dowiązań do danego pliku lub katalogu (liczba całkowita po opisie uprawnień) to zrobilibyśmy to np. tak:
$ ls -dla /etc/s* | sort -k2
-rw-r--r-- 1 root root 18480 sie 28 2008 /etc/services
-rw-r--r-- 1 root root 71449 sie 2 2008 /etc/sensors3.conf
-rw-r--r-- 1 root root 85602 lip 3 2008 /etc/sensors.conf
-rw-r--r-- 1 root root 1287 lis 22 2008 /etc/securetty
-rw-r--r-- 1 root root 2275 sty 11 2009 /etc/sysctl.conf
-rw-r--r-- 1 root root 2950 cze 29 2001 /etc/serial.conf
-rw-r--r-- 1 root root 155 mar 3 2010 /etc/shells
-r--r----- 1 root root 481 gru 1 2009 /etc/sudoers
-rw-r--r-- 1 root root 666 sie 25 2009 /etc/scsi_id.config
-rw------- 1 root root 854 gru 2 2009 /etc/shadow-
-rw-r----- 1 root shadow 854 lut 24 2010 /etc/shadow
drwxr-xr-x 2 root root 4096 paź 1 12:57 /etc/ssmtp
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/security
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/skel
drwxr-xr-x 2 root root 4096 paź 1 12:58 /etc/ssh
drwxr-xr-x 2 root root 4096 sty 11 2009 /etc/sysctl.d
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sane.d
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sgml
drwxr-xr-x 3 root root 4096 paź 1 12:58 /etc/sound
drwxr-xr-x 4 root root 4096 paź 1 12:58 /etc/ssl
Wykorzystaliśmy tu dodatkowo mechanizm "potokowania": pionowa kreska po pierwszym poleceniu (ls) powoduje przekazanie jego wyjścia jako wejścia do drugiego polecenia (sort). To z tego powodu w definicji separatora przy sortowaniu tablicy pionową kreskę ujęliśmy w apostrofy!
wc - Drukowanie informacji o zawartości pliku
Za pomocą polecenia wc można dowiedzieć się (nie otwierając pliku w żadnym edytorze tekstowym) informacji na temat ilości bajtów, słów, znaków, linii, oraz rozmiarze najdłuższej linii. Postać polecenia wygląda następująco.
Podstawowe użycie tego polecenia drukuje w następującej kolejności: ilość wierszy, ilość słów, ilość bajtów i nazwę pliku. Rysunek 1 ilustruje to.

Rys 1. Polecenie wc - Wyświetlanie informacji o pliku
Jeśli wpiszemy większą ilość plików, to każdy z osobna zostanie obsłużony, a na koniec zostanie wyświelona łączna ilość poszczególnych elementów (rysunek 2). Jeśli nie wpiszemy nazwy pliku, to program będzie czytał dane ze standardowego wejścia, a po zakończeniu wpisywania (CTRL-D) informacje zostaną wyświetlone.

Rys 2. Polecenie wc - Wyświetlanie informacji o plikach
Istnieje możliwość wyświetlania wybranych elementów osobno. Jeśli chcemy wyświetlić tylko ilość bajtów, to używamy opcji -c, jeśli interesuje nas ilość znaków to opcja -mprzychodzi z pomocą. Ilość wierszy sprawdzamy za pomocą -l. Długość najdłuższego wiersza uzyskamy za pomocą -L. Ilość wierszy to opcja -w. Wszystkie wspomniane opcje zostały pokazane na rysunku 3.

tr - Przetłumacz, albo usuń znaki
Polecenie tr umożliwia zmianę znaków na inne, usuwanie nadmiernej ilości znaków (np. spacji, kropek, itp.). Ogólna składnia polecenia ma się następująco:
Gdzie jako SET1 i SET2 rozumiemy znaki, które mają być wzorcami do zamiany. Jeśli narazie nie jest to jasne, nie ma co się przejmować, poniżej zostanie to wyjaśnione wraz z przykładami zastosowania polecenia tr.

Rys 1. Polecenie tr - Zmiana z małych na duże litery.
Jak widać na rysunku 1, podajemy nazwę polecenia - tr beż żadnych opcji, jako SET1 wpisujemy 'a-z', a jako SET2 'A-Z'. W ogólnej składni polecenia tr SET2 zosało napisane w nawiasach kwadratowych, a to dlatego, że nie jest wymagane przy niektórych opcjach polecenia tr (o tym za chwilę).
Jak to działa? A więc wpisujemy polecenie tak jak widoczne jest na rysunku 1. Terminal będzie czekał, aż wpiszemy tekst i wciśniemy enter. Po wciśnięciu klawisza enter, polecenie wykonuje swoją rolę. W tym przypadku tłumaczy (zamienia) wszystki pobrane znaki zawarte w przedziale 'a-z' na znaki zawarte w przedziale A-Z, czyli krótko mówiąc zmienia wielkość liter, z małych na duże.
W tym miejscu trzeba wspomnieć, że zakres znaków, które podajemy musi być odpowiedni, tzn. 'a-z' jest poprawnym zakresem, natomiast 'z-a' nie jest poprawnym zakresem i terminal wyświetli błąd:
Aby usunąć niektóre znaki, musimy je zdefiniować w SET1. W tym miejscu nie trzeba, a właściwie nie można ustawiać SET2, lecz trzeba ustawić opcję -d, która jest odpowiedzialna za znaki. Rysunek 2 pokazuje w jaki sposób można usunąć wszystkie kropki.

Rys 2. Polecenie tr - Usuwanie wszystkich kropek.
Opcja -s pozwala na usunięcie nadmiarowej ilości znaków ustawionych w SET1 i pozostawienie tylko jednego. Rysunek 3 pokazuje składnie i efekt działania tego polecenia.

Rys 3. Polecenie tr - Usuwanie nadmiarowej ilości kropek.
Polecenie Grep z wyrażeniami regularnymi
Polecenie grep (globally look for a regular expression end print – co na polski można przetłumaczyć: wyszukaj w pliku napisów spełniających wyrażenie regularne i wyświetl je) służy do znalezienia każdego wystąpienia słowa – ciągu znaków, frazy – w pliku utworzonym w systemie Linux. Ogólny wzór polecenia grep można przedstawić następująco:
grep [ opcja ] [ -e ] [ wzór ] [nazwa pliku]
Opcje
-b → wyświetla odnalezione miejsca
-c → wyświetla liczbę odnalezionych wyrażeń
-h → nie wypisuje nazwy plików przed każdym odnalezionym miejscem
-i → ignoruje różnice w wielkości liter
-l → wyświetla tylko nazwy plików w których odnaleziony został wzór
-n → wyświetla numer każdego wiersza, w którym został odnaleziony wzór
-s → brak wyświetlania jakichkolwiek komunikatów
-v → wyświetla tylko te wiersze, które nie zawierają wzoru
-w → wyświetla tylko te wiersz, w których wzór jest całym wyrazem
Kilka przykładów z poleceniem grep
$ grep -n ‘^piotr:’ /etc/passwd
Wyjaśnienie: polecenie grep wyświetla na ekranie wiersz z pliku /etc/passwd który definiuje użytkownika „piotr” i dodatkowo poprzedza wiersz jego numerem w pliku /etc/passwd
$ ls / | grep „^r.*”
Wyjaśnienie:
$ ls / grep „r.*”
Do nauki polecenia grep, które używane jest z wyrażeniami regularnymi musimy utworzyć plik pozwalający zaprezentować wszystkie możliwości zarówno polecenia grep jak i wyrażeń regularnych. Dane zawarte w tym pliku mogą wydawać się sztuczne lecz umożliwią nam one z względnie wystarczającym zapoznaniem się z omawianym tematem. Przy pomocy edytora vi (patrz rozdział IX) utwórzmy plik o nazwie dataplik:
Znaczenie danych zawartych w kolumnach
Kregkato KA Jan Kowalski 23 .98. \3\ 88
Kregkato KA Piotr Pawlak 23 .98. \3\ 88
Pregpod PO Krzysztof Wrak 25 .45. \2\ 77
Cregcent CE Jola Kruk 19 .74 \1\ 65
Mregmazu MA Urszula Kropiuk 14 .54. \5\ 85
Pregpod PO Zygmunt Malina 25 .45. \2\ 54
Wregwielko WK Marian Kluska 35 .98. \4\ 77
Greggda GD Katarzyna Polak 58 .69. \9\ 87
Cregcent CE Mariusz Pol 19 .54. \1\ 77
przypominam, że po wpisaniu danych naciskamy przycisk [Esc] następnie wystukujemy :, który ukazuje się w dolnym lewym rogu i wprowadzamy polecenie :wq . Plik dataplik jest utworzony i możemy go zacząć testować przy pomocy polecenia grep zawierającego lub nie zawierającego wyrażenia regularne.
Przykłady:
$ grep WK dataplik
Wregwielko WK Marian Kluska 35 .98. \4\ 91
Wyjaśnienie: Na ekranie wyświetlają się linie zawierające wyrażenie regularne WK znajdujące się w pliku dataplik
$ grep ‘^C’ dataplik
Cregcent CE Jola Kruk 19 .74 \1\ 65
Cregcent CE Mariusz Pol 19 .54. \1\ 25
Wyjaśnienie: Na ekranie wyświetlają się wszystkie linie zaczynające się od „C”, symbol ^ pokazuje ,że szukamy wierszy które zaczynają się od znaku (czy wyrażenia regularnego) znajdującego się zanim . W tym przypadku jest to litera C.
$ grep ‘4$’ dataplik
Pregpod PO Zygmunt Malina 25 .45. \2\ 54
Wyjaśnienie: Na ekranie wyświetlają się linie kończące się cyfrą „4”. Symbol $ pokazuje, że poszukiwania znaków rozpoczynamy od końca wiersza. W tym wypadku znakiem tym jest cyfra 4.
$
$ grep ‘4\. ’ dataplik
Cregcent CE Jola Kruk 19 .74. \1\ 65
Mregmazu MA Urszula Kropiuk 14 .54. \5\ 85
Cregcent CE Mariusz Pol 19 .54. \1\ 25
Wyjaśnienie: Na ekranie wyświetlają się linie zdefiniowane przez wyrażenie regularne zawierające zdefiniowane przez ‘4\. ‘ czyli wyszukujemy wierszy które zawierają cyfre cztery po której następuje kropka a następnie spacja.
$ grep ‘\\3\\’ dataplik
Kregkato KA Jan Kowalski 23 .98. \3\ 88
Kregkato KA Piotr Pawlak 23 .98. \3\ 88
Wyjaśnienie: Na ekranie wyświetlają się linie zawierające cyfrę „3” obramowaną przez \3\
$ grep ‘^[KW]’ dataplik
Kregkato KA Jan Kowalski 23 .98. \3\ 88
Kregkato KA Piotr Pawlak 23 .98. \3\ 88
Wregwielko WK Marian Kluska 35 .98. \4\ 91
Wyjaśnienie: Na ekranie wyświetlają się wszystkie linie zaczynające się o litery „K” albo „W”.
$ grep ‘[A-Z][A-] [A-Z][A-Z]
Kregkato KA AB Kowalski 23 .98. \3\ 88
Greggda GD DA Polak 58 .69. \9\ 87
Wyjaśnienie: Na ekranie wyświetlają się linie zawierające dwie duże litery następujące natychmiast po sobie po których występuje spacja i znów dwie duże litery następujące natychmiast po sobie.
$ grep ‘ll* ‘ dataplik
Cregcent CE Jola Krul 19 .74 \1\ 65
Cregcent CE Mariusz Poll 19 .54. \1\ 25
Wyjaśnienie: Na ekranie wyświetlają się linie zawierające małą literę „l” po której występuje zero lub więcej razy także mała litera „l” po której następuje spacja.
Polecenie Find
W tym podrozdziale omówimy szerzej – szczególnie z uwzględnieniem zastosowania w tym poleceniu wyrażeń regularnych - polecenie find (szukaj) z którym zapoznaliśmy się już w rozdziale 3. Polecenie find jest w realnym świecie porównywane do szwajcarskiego zegarka. Narzędzie to potrafi przeszukać wszystkie wpisy w systemie plików i wyświetlać rezultaty spełniające zadane kryteria. Pod wieloma względami te właśnie duże możliwości kryteriów, które możemy zastosować w polecenie find , przesądzają o potędze tego narzędzia.
Polecenie find jest bardzo przydatne do badania i wykonywania poleceń związanych z całą strukturą katalogów. Polecenie find przeszukuje system plików w dół począwszy od określonego katalogu, może również wykonywać podstawiając w nich jako argumenty wyszukane nazwy plików lub katalogów. Powtórzmy polecenie find prowadzi wyszukiwania plików lub katalogów według zadanych kryteriów od wskazanego katalogu „w dół” (jak pamiętamy struktura katalogu ma postać odwróconego drzewa), uwzględniając wszystkie podkatalogi, z czego wynika, ze jeżeli wskazanym katalogiem jest root ( / ) to wówczas przeszukujemy całą strukturę katalogów systemu Linux.
Polecenie find wyszukuje pliki w strukturze katalogu (katalogów) i może na wyszukanych plikach wykonywać różne operacje, dlatego strukturę polecenia find można przedstawić w następujący sposób:
find - w jakim katalogu wyszukujemy pliki – jakie kryteria selekcji – co robimy ze znalezionymi plikami ?
Weźmy najprostszy przykład:
find /…… → oznacza, ze wyszukiwania będą odbywały się w całej strukturze katalogów.
find /home….. → oznacza, że wyszukiwania będą odbywały się w katalogu domowym home.
Jakimi kryteriami selekcji dysponujemy w poleceniu find ?
Kryteria → Funkcja
-name → wyszukuje plik o określonej nazwie
-type → wyszukuje pliki, których typ jest określony jako:
d → katalog
f → plik normalny
b → plik blokowy
c → plik znakowy
l → dowiązanie symboliczne
-path ‘wzorzec’ → wyszukuje pliki, których ścieżka dostępu pasuje do wzorca
-links → wyszukuje pliki z liczbą N dowiązań do plików
-size → wyszukuje pliki, które mają wielkość N
-user → wyszukuje pliki, które należą do użytkownika
-perm → wyszukuje pliki, które mają prawa dostępu określone jako tryb
-atime → wyszukuje pliki, które były otwierane w N dniach
-mtime → wyszukuje pliki które zostały zmodyfikowane w N dniach
Co robimy z wyszukanymi plikami czyli jakie są kryteria egzekucji na plikach wyselekcjonowanych przez polecenie find ?
-print → przekazuje na standardowe wyjście nazwę odnalezionego pliku oraz jego pełną ścieżkę dostępu
-exec polecenie {}\; → uruchamia polecenie dla odnalezionego pliku
-ok. polecenie {} \; → potwierdza uruchomienie polecenia dla odnalezionego pliku
Z dotychczasowego wykładu wynika, że polecenie find może przybrać postać niezwykle skomplikowaną, dlatego najlepszą metodą jego nauki będzie analiza poniższych przykładów, które stopniując trudność umożliwią uczniowi zapoznanie się z skomplikowana strukturą polecenia.
$ find . –type d
Polecenie wyszukuje tylko katalogi znajdujące się w bieżącym katalogu (bieżący katalog jest oznaczony w poleceniu „.”.
$ find . –name piotr1 –print
Polecenie to wyszukuje wszystkie pliki o nazwie piotr1
$ find . –type d -print
Polecenie to wyszukuje tylko nazwy katalogów
$ find /home –name ‘*.c’ –print
Polecenie to wyszukuje wszystkie pliki których sufiks jest „.c”
$ find ~ -name ‘p*’ –print
W powyższym poleceniu tylda „~” oznacza katalog domowy użytkownika czyli punkt rozpoczęcia poszukiwań. Polecenie znalazło jeden plik którego nazwa zaczyna się na „p” (wzorzec p*).
Uwaga: czy możemy kryterium egzekucji –print, zastąpić używając innego wyrażenia; inaczej mówiąc czy możliwe jest uzyskanie tego samego rezultatu innym sposobem, wykorzystując dotychczas poznane polecenia i zasady obowiązujące w systemie Linux ? Tak, poznaliśmy w rozdziale III tzw. potok (pipe) i wykorzystując jego mechanizm, przy pomocy np. polecenia more lub cat, otrzymamy te same rezultaty
$ find . –name piotr1 | more
$ find . –type d | more
$ find /home –name ‘*.c’ | more
$ find ~ -name ‘p*’ | more
Wniosek jest banalny ale bardzo ważny: ten sam rezultat możemy uzyskać stosując różne polecenia i różne mechanizmy wewnętrzne systemu operacyjnego Linux.
Polecenie find może również sprawdzać warunki dotyczące nazwy i podejmować odpowiednie działania. Aby na przykład zmienić prawa dostępu wszystkich podkatalogów katalogu domowego /home, można wydać polecenie
$ find . –type d –exec chmod 770 {} \;
Uwaga: używając opcji -exec należy zachować szczególna ostrożność ponieważ można po niej podać cokolwiek - w tym polecenie mv, rm itd. Jeżeli zamiast opcji –exec użyjemy opcji –ok., przed każda operacją wymagane będzie potwierdzenie
$ find . –type d -ok. chmod 770 {} \;
find poprosi użytkownika o potwierdzenie , zanim wykona polecenie.
Dotychczas przedstawiliśmy względnie prostą postać polecenia find , w tej chwili wprowadzimy jeszcze dwie dodatkowe grupy kryteriów.
Pierwszym z nich są parametry kryteriów, które wyrażają ilość lub wielkość mogą one przybierać trzy różne formy:
1. Kryterium n oznacza dokładnie liczba symbolizująca n, tak więc „-ctime 5” wyraża że plik był utworzony 5 dni temu
2. Kryterium –n oznacza, mniejszy od liczby symbolizującej n, tak więc „-size -1000”, wyszukuje pliki których objętość jest mniejsza od 1000 octetów
3. Kryterium +n oznacza, większy od liczby symbolizującej n, tak więc „-size +1000” wyszukuje pliki których objętość jest większa od 1000 octetów.
Drugim z nich są parametry logiczne, które np. mogą wiązać wiele kryteriów wyborów; z definicji operatorem logicznym wiążącym różne kryteria wyboru jest ET (i), jednak istnieją także inne operatory:
Operator logiczny Jego oznaczenie w poleceniu find
ET -a
OU -o
NON !
(wyrażenie) \(wyrażenie\)
Kontynuujemy wyjaśnianie działanie polecenia find na przykładach:
$ find /home -mtime 0 –print
$ find /home –type f -size 0 –exec rm –f {}\;
Polecenie wyszukuje i niszczy wszystkie pliki, których objętość wynosi 0 octetów, czyli pliki puste. Zwróćmy uwagę, że te – jego rezultaty - polecenie można uzyskać w inny sposób:
$ rm ‘find /home –type f –size 0 -print’
$ find /home ! –user piotr1 \( -size +10000c –o –atime -30\)
Polecenie wyszukuje pliki których właścicielem (użytkownikiem) nie jest piotr1 i których objętość nie przekracza 10000 octetów i które używano przed 30 dniami
$ find . –mtime +20 -exec rm {} \;
Polecenie to pozwala wymazać pliki, które nie były modyfikowane od więcej niż 20 dni.
To samo można wyrazić za pomocą:
$ rm ‘find . mtime +20 -print’