Systemy uniksowe oferują kilka przydatnych poleceń służących do wyszukiwania plików, ciągów tekstu, które w połączeniu z przedstawionymi powyżej strumieniami i przekierowaniami oraz z wyrażeniami regularnymi stanowią bardzo potężne narzędzie administratorskie.
1. Wyrażenia regularne
Wyrażenia regularne są wzorcami opisującymi, zastępującymi łańcuchy tekstów, zostały one wprowadzone od samego początku istnienia Uniksa przez jednego z jego twórców — Kena Thompsona. Wyrażenia regularne są bardzo efektywnym sposobem pracy z tekstem i zdecydowanie warto je opanować.
Symbol | Zastępuje |
---|---|
. | dowolny znak |
^ | dopasuj występujące po operatorze wyrażenie do początku wiersza |
$ | dopasuj poprzedzające wyrażenie do końca wiersza |
\x | znaki specjalne, gdzie x to znak specjalny np. \$ zastąpi znak dolara |
[lista] | zastępuje dowolny znak spośród tych wymienionych na liście, mogą to być przedziały np. [0-9] lub [a-d] |
() | grupowanie wyrażeń regularnych |
? | dokładnie jeden element wcześniejszy |
a|b | dopasuje wyrażenie a lub wyrażenie b |
* | dopasuj zero lub więcej wyrażeń znaku poprzedzający operator |
+ | jeden lub więcej elementów poprzedzających operator |
2. Wyrażenia regularne a znaki globalne
Warto nadmienić że, bash do wersji 3.0 nie miał wbudowanej obsługi wyrażeń regularnych, które to były wykorzystywane przez programy pracujące na strumieniach tekstu np.: sed, awk czy też grep. Za to wbudowana była obsług wyrażeń globalnych i znaków wieloznacznych (ang. wildcards).
Symbol | Zastępuje |
---|---|
* | dowolny ciąg znaków |
? | dokładnie jeden znak |
[lista] | zastępuje dowolny znak spośród tych wymienionych na liście, mogą to być przedziały np. [0-9] lub [a-d] |
[^lista] | wybrane zostaną znaki, które nie są na liście |
{} | grupuje wyrażenie globalne |
Wyrażenia regularne pozwalają wyszukać dany łańcuch w strumieniu tekstu, podczas gdy wyrażenia globalne zastępują fragmenty tekstu. W poniższym, bardzo prostym przykładzie usunięto wszystkie plik rozpoczynające się na literę “a”.
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ ls
aa abc nowy.txt przykład.txt
ab error.txt polecenie.txt wszystko_o_konsoli.txt
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ rm a*
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ ls
error.txt nowy.txt polecenie.txt przykład.txt wszystko_o_konsoli.txt
W tym natomiast usunięto wszystkie które nie mają jako pierwszej litery z zakresu b do z i dalsza ich nazwa to dowolny ciąg znaków.
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ ls
aa abc nowy.txt przykład.txt
ab error.txt polecenie.txt wszystko_o_konsoli.txt
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ rm [^b-z]*
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ ls
error.txt nowy.txt polecenie.txt przykład.txt wszystko_o_konsoli.txt
3. grep
grep to powszechnie wykorzystywany program do wyszukiwania w strumieniu wejścia ciągów tekstowych, pasujących do podanego wyrażenia regularnego. Występuje on w każdym systemie uniksowym a jego autorem jest Ken Thompson.
grep ma kilka przydatnych parametrów:
- -c — wyświetla tylko liczbę znalezionych linii,
- -n — wyświetlany jest numer linii w pliku, w którym znaleziono dany ciąg znaków,
- -w — wyszukuje tylko całe słowa,
- -x — wyszukuje tylko całe linie.
adam@laptop:~/Dokumenty/jakilinux.org/przykłady$ dmesg | grep Mouse
[ 15.436000] input: USB-PS/2 Optical Mouse as /class/input/input2
[ 15.436000] input: USB HID v1.10 Mouse [USB-PS/2 Optical Mouse]
on usb-0000:00:1d.0-2
W powyższym przykładzie wyjście polecenia dmesg (wyświetlającego informacje dziennika zdarzeń jądra systemu) przekierowałem za pomocą potoku (operator |) do polecenia grep, gdzie jako wyrażenia regularnego użyłem słowa “Mouse” (wielkość liter ma znaczenie). Polecenie przefiltrowało wejście i wyświetliło jedynie te linie, które zawierają słowo “Mouse”.
Do kolejnych przykładów załóżmy, że mamy plik tekstowy, wyrażenia.txt o zawartości:
1. owoc
2. rower
3. dom
4. auto
5. płyta
ananas
Tak więc:
grep ^[1-6]..a wyrażenia.txt
4. auto
ananas
Powyższe wyrażenie wyszuka wszystkie łańcuchy, które zaczynają się od liczb z przedziału od 1 do 6, dalej zawierają dwa dowolne znaki (w naszym przypadku kropkę i spację), dalej zawierają literę “a”, za nią dowolny już ciąg znaków.
Wyrażenie poniżej wyświetli każdą linię kończącą się na literę “a”.
grep a$ wyrażenia.txt
5. płyta
grep a.*a wyrażenia.txt
ananas
Powyższe wyrażenie wyszuka dowolny ciąg zaczynający się na a, dalej zawierający dowolny ciąg znaków, i kończący się na a. W tym przypadku warto zwrócić uwagę na zapis “.*”. Jak pamiętamy, znak * w wyrażeniach regularnych zwróci zero lub więcej znaków poprzedzających ten operator, natomiast operator . oznacza dowolny znak. Ujmując to prościej, wyszukujemy w ten sposób zero lub więcej wystąpień dowolnego znaku.
grep "\(1\|4\)" wyrażenia.txt
1. owoc
4. auto
Przedstawione powyżej wyrażenie, jest i tyle ciekawe, że użyto w nim znaków, które bash traktuje jako znaki specjalne. Aby to ominąć, postawiłem przed nimi znak \, a całość zamknąłem w cudzysłów, aby uniknąć interpretowania przez bash tego wyrażenia (zrobi to grep).
Tematyka wyrażeń regularnych jest bardzo rozbudowana, dlatego zachęcam do samodzielnego eksperymentowania i ćwiczeń.
4. find
Polecenie find przeszukuje drzewo katalogów w poszukiwaniu plików lub katalogów o podanej nazwie lub jej części, lub o podanych kryteriach takich jak: rozmiar, typ, właściciel plików, data utworzenia lub data ostatniej modyfikacji. Najprostsze wywołanie programu find może wyglądać następująco:
adam@laptop:~$ find . -name linux
./Downloads/Firefox/vmware-server-distrib/lib/perl5/\\
site_perl/5.005/i386-linux/linux
./Downloads/Firefox/tp_smapi-0.31/include/linux
Składnia tego polecenia jest następująca: find katalogi_startowe kryterium wyszukiwania i operacje, które należy wykonać na wyszukanych elementach. W powyższym przykładzie katalogiem startowym jest katalog bieżący, jak już wcześniej wspominałem każdy katalog zawiera dowiązanie do siebie samego reprezentowane przez kropkę, oraz kryterium wyszukiwania — wszystkie pliki i katalogi zwierające frazę “linux”. Wyszukiwanie rozpoczyna się od katalogu startowego i postępuje w dół drzewa katalogów, tzn. najpierw katalog bieżący, a potem jego podkatalogi, oczywiście o ile ma się prawo do ich odczytu. W programie find można (i warto a wręcz należy) używać znaków globalnych przedstawionych wcześniej.
find umożliwia wyszukiwanie według typu.
adam@laptop:~$ find . -type d
Powyższy przykład wyszuka wszystkie katalogu znajdujące się w bieżącej lokalizacji. Kryteria oczywiście można łączyć.
adam@laptop:~$ find . -type d -name Dokumenty
./Dokumenty
./Dokumenty/jakilinux.org/Dokumenty
Powyższe wywołanie znajdzie wszystkie katalogi w bieżącej lokalizacji zawierające w swej nazwie zwrot “Dokumenty”. Możliwe typy plików przedstawia poniższa tabela.
Parametr | Rodzaj pliku |
---|---|
b | urządzenie blokowe |
c | urządzenie znakowe |
d | katalog |
f | zwykły plik |
l | dowiązanie symboliczne |
s | gniazdo (ang. socket) |
find wywołany z parametrem -size wartość, wyszuka pliki o wielkości podanej w parametrze wartość, jeżeli do wartości dodamy znak + (np. -size +wartość), program wyszuka pliki większe od podanej wartości. Jeżeli dodamy znak - (np. -size -wartość), wyszukane zostaną pliki mniejsze od podanej wartości. Domyślna wartość to 512 bitowe bloki, pozostałe wartości to:
- c — bajty,
- k — kilobajty,
- M — megabajty,
- G — gigabajty.
W poniższym przykładzie zostaną wyszukane wszystkie pliki o rozmiarze większym niż 100 MB ale mniejszym niż 200 MB.
adam@laptop:~$ find . -size +100M -size -200M
./plan9_07010zip
Pozostałe kryteria wyszukiwania przedstawia poniższa tabela.
-atime n | Ostatni dostęp miał miejsce n dni temu |
-mtime n | Plik został zmodyfikowany n dni temu |
-newer plik | Wyszukiwany plik został zmodyfikowany wcześniej niż podany plik |
-links n | Plik zawiera dokładnie n twardych dowiązań |
-perm p | Plik ma uprawnienia, gdzie p to liczbowy tryb dostępu |
-user użytkownik | Właścicielem pliku jest użytkownik |
-group grupa | Właścicielem pliku jest grupa |
-empty | Puste pliki |
Opcje liczbowe można poprzedzać znakami + i -, które oznaczają odpowiednio “więcej niż” oraz “mniej niż”, podobnie jak miało to miejsce w kryterium time opisanym wcześniej.
Jak już wcześniej wspominałem, polecenie find może wykonać określone operacje na plikach, które znajdzie. Domyślną operacją jest -print, która wypisuje nazwy łacznie z adresami plików. W niektórych powłokach należy dodawać tę opcję za każdym razem.
Kolejna możliwa akcja to -ls, która wypisuje informacje o plikach w ten sam sposób, co polecenie ls uruchomione z parametrami -lids. Ostatnia możliwość to uruchomienie z parametrem -exec i wykonanie dowolnego polecenia na znalezionych plikach.
adam@laptop:~$ find . -size +100M -size -150M -ls
2485508 115744 -rw-r--r-- 1 adam adam 118398976 maj 2 22:44
./plan9/plan9_compressed.img
find . -size +110M -size -150M -exec cp {} /home/adam/pliki/ \;
Pierwszy z powyższych przykładów, jak widać, wypisze szczegółowe dane wyszukanych plików. Drugi jest ciekawszy i wymaga dokładniejszej analizy. find wykona na plikach operację podaną wraz z parametrem. W tym przypadku, wszystkie pliki większe niż 110 MB i mniejsze niż 150 MB zostaną skopiowane do katalogu pliki, podwójny nawias klamrowy {} oznacza, że operacja ma być wykonana na każdym pliku a \ przed ; chroni przed błędną interpretacją polecenia przez powłokę.
find ma jeszcze inne ciekawe opcje: -ok — działa podobnie jak -exec z tą różnicą, że przed każdą operacją użytkownik proszony jest o potwierdzenie działania, -prune powoduje, że find nie wchodzi do żadnego z napotkanych katalogów.
Składnia find umożliwia tworzenie złożonych wyrażeń, łączenia kryteriów. Domyślnie kryteria łączone są za pomocą logicznej koniunkcji (AND): (-a). Wszystkie kryteria muszą być spełnione, aby plik został uznany za zgodny z kryteriami. Operator łączenia alternatywy logicznej (OR): -o, natomiast operator negacji to: \! Istnieje możliwość wykorzystania nawiasów w celu grupowania kryteriów \( \).
Ważnym parametrem polecenia find jest parametr -print0, w przypadku jego użycia, nazwy znalezionych plików nie są rozdzielane znakiem nowej linii a znakiem null. Rozpatrzmy przykład poniżej, w którym użyjemy dwóch plików: raport czerwiec.txt i raportczerwiec.txt.
adam@laptop:~$ find . -name "raport*" | xargs rm
rm: nie można usunąć `./raport': No such file or directory
rm: nie można usunąć `czerwiec.txt': No such file or directory
Poleceniu rm nie udało sie usunąć pliku raport czerwiec.txt, ponieważ zawiera on spację w nazwie i jego nazwa została w tym miejscu rozdzielona.
find . -name "raport*" -print0 | xargs -0 rm
Polecenie print otrzymało opcję -print0, natomiast polecenie xargs opcję -0, dzięki czemu bez problemu usunięty został plik zawierający spację. Uwaga! Opcja -print0 dostępna jest tylko w wersji GNU polecenia find.
Brak komentarzy:
Prześlij komentarz