W internecie dostępnych jest mnóstwo rozwiązań pozwalających na tworzenie szczegółowych statystyk odwiedzin stron WWW. Wiele z nich potrafi wyświetlać informacje nie tylko na temat ruchu, ale także preferencji użytkownika. Czasem jednak to nie wystarcza. Wówczas przydaje się skrypt skrojony na miarę.
W większości gotowych systemów statystyk
mamy dostęp tylko do tych informacji,
które autor uznał za wartościowe. Co
jednak zrobić wtedy, gdy interesują nas dane
dotyczące ruchu na całym serwerze? I to nie byle
jakie, bo dostosowane do indywidualnych potrzeb,
uwzględniające specyficzne filtry lub modyfikatory.
Celem tego artykułu jest zaprezentowanie
sposobu analizowania logów serwera Apache oraz
generowania wykresów przedstawiających różne
aspekty obciążenia serwera. Dzięki potędze języka
AWK pokażę, jak w prosty sposób zgłębiać dane
tabelaryczne oraz dynamicznie rysować wykresy
za pomocą narzędzia GnuPlot.
Czym jest AWK?
AWK to interpretowany język programowania
przypominający swoją składnią pochodne języka
C. Jego głównym zastosowaniem jest wyszukiwanie
i przetwarzanie wzorców znajdujących się
w tekście. Najczęściej stosuje się go do analizy
danych tabelarycznych, czyli takich, które mają
jednolitą strukturę i mogą być w łatwy sposób
odseparowane.
AWK jest dość starym językiem, który na
samym początku swojego istnienia działał tylko na
systemach klasy UNIX. Dzisiaj dostępny jest jednak
dla wielu platform nie tylko Linuksa, ale także Mac
OS oraz Windows (za pomocą cygwina).
Struktura skryptu
Język AWK ma czteroelementową strukturę.
Na początku definiowane są zmienne globalne
oraz stałe. Kolejne miejsce zajmują deklaracje
oraz implementacje funkcji. Później umieszczone
są sekwencje definiujące wzorce, wyszukiwane
w tekście oraz przyporządkowane im akcje. Na
samym końcu znajduje się kod odpowiedzialny za
wykonanie czynności finalizujących pracę skryptu.
W praktyce wymagana jest tylko przedostatnia
sekcja. Większość prostych skryptów można
bowiem zrealizować z wykorzystaniem samych
deklaracji typu wzorzec-akcja.
Przykładowa struktura skryptu AWK:
#Ścieżka dostępu do interpretera język AWK
#!/usr/bin/awk -f
#Kod inicializujący i deklarujący zmienne
BEGIN {
}
#Definicje funkcji
function nazwa_funkcji() {}
#Sekwencje typu wzorzec-akcja wzorzec {AKCJA}
#Kod wykonywany pod koniec analizowania danych
END {
}
Skrypty AWK analizują pliki linia po linii.
W przypadku dopasowania odpowiedniego wzorca
uruchamiana jest przypisana do niego akcja. Możliwe
jest także dokonanie analizy z pamięcią (tzw.
multiline parsing). Tematyka ta leży jednak poza
zakresem tego artykułu.
Przykładowy skrypt
Mając niewielkie podstawy teoretyczne,
warto pokusić się o napisanie prostego skryptu
analizującego wskazany plik tekstowy. Załóżmy, że
mamy do dyspozycji plik, w którym gromadzimy
informacje na temat opublikowanych przez nas
artykułów. Przykładowa struktura może wyglądać
tak jak poniżej:
Magazyn INTERNET 4 Zaawansowane formularze
Internet Maker 6 J2ME
Magazyn INTERNET 3 Biblioteka GD
Magazyn INTERNET 4 Sklepy Internetowe
Internet Maker 2 QuickForms
Dane w pliku mają postać tabelaryczną. Można
więc wyróżnić trzy kolumny oraz pięć rekordów.
Separatorem kolumn jest znak tabulacji. Pierwsza
kolumna reprezentuje nazwę czasopisma, w którym
został opublikowany artykuł, druga to liczba
stron , a ostatnia jest tytułem publikacji.
Istnieje kilka cennych informacji, które można
wydobyć z podanego pliku. Jednak najłatwiej jest
policzyć liczbę opublikowanych artykułów oraz ich
objętość w czasopiśmie, grupując przy tym publikacje
według magazynów. Skrypt przedstawiony
na poniższym listingu pokazuje jeden z możliwych
sposobów rozwiązania tego problemu.
Znacznik $
AWK umożliwia dostęp do dowolnej kolumny
danych pliku źródłowego. Służy do tego znacznik
dolara, poprzedzający odpowiedni numer kolumny.
W podanym przykładzie $2 odnosi się do drugiej
kolumny zawierającej liczbę stron artykułu.
Jak łatwo się domyślić, odniesienia tego można
używać zarówno w sekcji akcji, jak i wzorca.
Oto prosty skrypt AWK analizujący dane
z publikacjami (publikacje.awk), zawarty także na
listingu 1.
#!/usr/bin/awk -f
BEGIN {
FS=\"\t\"
num_mi_arts = 0
num_im_arts = 0
num_mi_pages = 0
num_im_pages = 0
}
/Magazyn INTERNET/ { num_mi_arts++;num_mi_pages+= }
/Internet Maker/ { num_im_arts++; num_im_pages += }
END {
print(\"Magazyn INTERNET\")
printf(\"Ilosc artykulow: %d, stron: %d\n\", num_mi_arts, num_mi_pages)
printf(\"Internet Maker\n\")
printf(\"Ilosc artykulow: %d, stron:%d\n\", num_im_arts, num_im_pages)
}
Najpierw następuje wskazanie interpretera
skryptu AWK. Opcja -f pozwala na uruchomienie
skryptu z konsoli i użycie pliku z danymi jako
argumentu:
#!/usr/bin/awk -f
Potem ma miejsce ustawienie separatora
pól (Field Separator) na znak tabulacji. Od tego
momentu dane w pliku wejściowym dzielone są ze
względu na ten znak. Kolejne linie definiują oraz
inicjalizują zmienne odpowiedzialne za zliczanie liczby publikacji oraz stron artykułów w Magazynie
INTERNET oraz Internet Makerze:
BEGIN {
FS=\"\t\"
num_mi_arts = 0
num_im_arts = 0
num_mi_pages = 0
num_im_pages = 0
}
Teraz ma miejsce rozpoczęcie sekcji wzorców.
Wzorzec zdefiniowany jest pomiędzy znakami
ukośników. W tym przypadku jest nim zwykły tekst
– można jednak posłużyć się dowolnym wyrażeniem
regularnym. W momencie dopasowania
wskazanego wzorca wykonywana jest akcja zdefiniowana
w nawiasach klamrowych (zwiększenie
odpowiednich liczników):
/Magazyn INTERNET/ { num_mi_arts++;num_mi_pages+= }
/Internet Maker/ { num_im_arts++; num_im_pages += }
Ostatni etap to finalizacja działania skryptu,
czyli wyświetlenie tekstu z podsumowaniem. Dzięki
zastosowaniu funkcji printf (znanej także z C)
możliwe jest wyświetlenie formatowanego tekstu:
END {
print(\"Magazyn INTERNET\")
printf(\"Ilosc artykulow: %d, stron:
%d\n\", num_mi_arts, num_mi_pages)
printf(\"Internet Maker\n\")
printf(\"Ilosc artykulow: %d, stron:
%d\n\", num_im_arts, num_im_pages)
}
Skrypt z listingu 1 może zostać uruchomiony za
pomocą komendy:
./publikacje.awk dane.txt
po wcześniejszym nadaniu praw wykonywalności
za pomocą polecenia:
(chmod +x publikacje.awk)
Złożenie wszystkiego w całość
Uwzględniając poprawną strukturę skryptu
AWK (przedstawioną wcześniej), można w łatwy
sposób skleić wszystkie zaprezentowane części
w jedną całość. Stworzony w ten sposób skrypt
najlepiej jest zapisać do pliku webAnalytics.awk
i nadać mu prawa wykonania (chmod +x webAnalytics.awk).
Wywołanie polecenia: ./webAnalytics.awk
access.log | gnuplot, powinno wygenerować plik
graficzny PNG zawierający zestawienie transferu
dla aktualnego dnia. Plik będzie miał postać:
transfer_DD_MMM_YYYY.png. Oczywiście zamiast
access.log należy podać ścieżkę dostępu do logów
Apache\’a zapisanych na konkretnej maszynie. Jeżeli
w logach nie ma wpisów dla danego dnia, wówczas
zostanie wygenerowany pusty wykres.
Istnieje również możliwość zautomatyzowania
generowania wykresów. Można to zrobić poprzez
dodanie skryptu do aplikacji typu cron. W ten sposób
możliwe jest zaprogramowanie cyklicznego generowania
wykresów. Stworzone tak rysunki mogą
być dynamicznie linkowane za pomocą skryptu
PHP i wyświetlane na wskazanej stronie WWW.
Opisany tutaj skrypt wraz z przykładowym
logiem Apache\’a oraz wygenerowanymi obrazkami
został zamieszczony w zał±czniku.
Zakończenie
W ten oto sposób udało się stworzyć prosty
skrypt analizujący logi serwera Apache i generujący
wykres zależności transferu od pory dnia. Z racji
na ograniczoną objętość artykułu nie opisałem
wszystkich zagadnień związanych z językiem AWK.
Zaprezentowany skrypt jest tylko wierzchołkiem
góry lodowej i zawiera jedynie ułamek informacji,
jakie można wydobyć z logów Apache\’a.
W ramach ćwiczeń i lepszego poznania
opisanych tutaj technologi warto wzbogacić całość
o możliwość analizy unikalnych wyświetleń strony
oraz tzw. przeładowań (unique & hit).
Można również zająć się analizą przeglądarek internetowych,
za pośrednictwem jakich internauci oglądają stronę
oraz informacjami na temat najpopularniejszych
dokumentów. Możliwości jest bardzo dużo. Aby je
poznać, zachęcam wszystkich do analizy drugiej
(rozbudowanej) wersji skryptu.
ZALACZNIK!
Przydatne linki
GnuPlot
http://www.gnuplot.info
Strona domowa programu GnuPlot. Można
z niej pobrać najnowszą wersję tego narzędzia
oraz zapoznać się z kursami tworzenia wykresów.
Gawk
http://www.gnu.org/software/gawk/
Odmiana programu AWK, dostępna
w większości popularnych dystrybucji Linuksa.
Oprócz najnowszej wersji, na stronie udostępniono
również obszerny przewodnik.
\”Śledzenie\” Apacza
Nie każdy wie o tym, że serwer WWW, jakim
jest Apache, ma wbudowany system logujący,
który zapisuje praktycznie wszystkie dane, jakie
możemy uzyskać o danym użytkowniku. Przede
wszystkim są to informacje na temat adresu IP jego
komputera, przeglądarki internetowej, systemu
operacyjnego, daty wejścia, przeglądanego dokumentu,
a nawet używanego protokołu. Wszystkie
z tych informacji zapisywane są do pliku zwanego
logiem. Każde odwołanie do serwera WWW dopisuje
linię ze wspomnianymi wyżej informacjami.
Jak można się domyśleć, dane te mają charakter
tabelaryczny, gdzie za separator można przyjąć
znak spacji.
Plik z logami
Lokalizacja pliku z logami Apache może nie być
taka sama we wszystkich dystrybucjach Linuksa.
Najczęściej można go jednak znaleźć w jednym
z podkatalogów /var/log/
Przykładowa linia logu Apache\’a może wyglądać
tak jak poniżej:
83.19.178.186 - - [30/Sep/2007:09:03:28 +0200] \"GET /favicon.ico HTTP/1.1\" 404 292 \"-\" \"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\" \"-\"
Stosując spację jako znacznik separatora oraz
analizując dane za pomocą AWK, można uzyskać
dostęp do odpowiednich kolumn dzięki przykładowym
referencjom:
- $1 – Adres IP komputera
- $4 – Dokładna data zapytania
- $6 – Rodzaj zapytania HTTP ( GET/POST)
- $7 – Dokładna ścieżka do pliku, który został pobrany
- $9 – Używana wersja protokołu HTTP
- $10 – Rozmiar pobieranego pliku
Statystyki Ruchu – webAnalytics
Przyszedł czas, aby wykorzystać zdobytą
wiedzę w bardziej złożonym projekcie. Mając do
dyspozycji plik z logami Apache oraz narzędzia
AWK i GnuPlot, jesteśmy w stanie narysować wiele
wykresów, ukazujących różnego rodzaju zależności.
Nasz wykres przedstawiać będzie rozkład godzinny
zużywanego transferu dla aktualnego dnia.
Jak łatwo jest się domyślić, argumentami wykresu
są godziny z zakresu 0-23. Wartość funkcji to nic innego, jak liczba przesłanych megabajtów, która
jest po prostu sumą transferów o danej godzinie.
Wykres zostanie narysowany poprzez połączenie
odpowiednich punktów liniami prostymi.
Najtrudniejszym elementem tworzenia skryptu
AWK jest wydobycie odpowiednich danych z pliku.
Nie zawsze jest to tak łatwe, jak w przedstawionym
wcześniej przykładzie. Stworzenie właściwej
definicji typu wzorzec-akcja wiąże się często
z wykorzystaniem wyrażeń regularnych. Pomagają
one w stworzeniu uogólnień dla danego łańcucha
znaków.
Stosując znak spacji jako separator pól, można
dostać się do danych, które po odpowiedniej
przeróbce zostaną wykorzystane do wygenerowania
wykresu. W ten oto sposób rozmiar pobranego
pliku oraz data wykonania zapytania znajdą się
odpowiednio pod referencjami $10 i $4.
Rozmiar pliku ($10) jest zawsze liczbą. Warto
jest więc przeprowadzić odpowiednią walidację
tego pola za pomocą wyrażenia regularnego.
Zapis: $10 ~ /^[0-9]+$/, tworzy wzorzec AWK
porównujący wyżej wspomniane pole do wartości
numerycznej. Gdy dopasowanie okaże się poprawne,
wykonywana jest akcja znajdująca się pomiędzy
znacznikami nawiasów klamrowych. W tym
przypadku odpowiedzialna jest ona za policzenie
rozmiaru plików przesłanych w konkretnym dniu
oraz godzinie dnia. Funkcję licznika najlepiej spełni
tablica asocjacyjna, której kluczem będzie data,
a wartością liczba przesłanych bajtów.
Ponieważ liczone będą dwa typy wartości,
najłatwiej jest użyć dwóch tablic:
- trafficByDate – zawierającej sumę przesłanych
danych dla danego dnia, indeksowanej według
klucza o formacie: DD/MMM/YYYY. - trafficByDateHour – zbierającej szczegółowe
informacje o rozkładzie dobowym transferu
dla wskazanego dnia. Kluczem tej tablicy jest
łańcuch znaków w formacie: DD/MMM/YYYY,GG.
Jedyną rzeczą, której brakuje w całej układance,
jest wyodrębnienie odpowiednich elementów daty
z pola określonego referencją $4. Dzięki zastosowaniu
funkcji substr oraz index można w łatwy
sposób oddzielić część daty określoną wzorcem
DD/MMM/YYYY. W podobny sposób, stosując
funkcję split i znacznik dwukropka jako separator,
uzyskamy dostęp do pozycji zawierającej godzinę.
Kompletną definicję typu wzorzec-akcja dla
danych o rozmiarze pliku zawarto poniżej:
~ /^[0-9]+$/ {dateStr = substr(,2, index(,\":\")- 2 )split(,buf,\":\")trafficByDate[dateStr] += trafficByDateHour[dateStr \",\" buf[2]]+=}
Warto również stworzyć funkcję pomocniczą,
której zadaniem będzie generowanie tablicy
asocjacyjnej zawierającej godziny z przedziału
0-23. Pojedyncze cyfry zostaną poprzedzone
zerem w celu zachowania kompatybilności
z formatem daty określonym przez pliki logów
Apache. Funkcja ta zostanie wykorzystana później,
w czasie generowania wykresów, tak aby w łatwy
sposób przeiterować po wszystkich godzinach dla
wskazanej daty.
Kod funkcji pomocniczej:
function getHourArr() {
for( hr = 0; hr < 24; hr++)
{
if ( hr < 10 )
hourArr[\"0\" hr] = \"0\" hr
else
hourArr[hr] = hr
}
}
Ważnym fragmentem skryptu jest funkcja
gnuplotDailyTransfer odpowiedzialna za genero-wanie instrukcji rysujących wykres - przekazanych
do programu GnuPlot. Jej zadanie polega przede
wszystkim na wyświetleniu sekwencji odpowiednich
komend na konsolę. Odbywa się to za pomocą
instrukcji print. Uzyskane w ten sposób dane
można w łatwy sposób przekierować do programu
GnuPlot za pomocą symbolu \"pipe\".
Ponadto warto wspomnieć o tym, że funkcja
przyjmuje jeden argument, którym jest data
podana w formacie DD/MMM/YYYY (na przykład:
08/Feb/2008). W przypadku standardowego uruchomienia
skryptu do funkcji przekazana zostanie
aktualna data, służąca do wygenerowania wykresu
dla bieżącego dnia.
Kod odpowiedzialny za rysowanie wykresu
przedstawiony został na listingu 3. Poniżej omówienie
najważniejszych fragmentów.
function gnuplotDailyTransfer(date) {
outputFileName = \"transfer_\" date \".png\";
gsub(\"/\",\"_\", outputFileName);
print \"set terminal png\"
print \"set autoscale\"
print \"set title \\"Statystyki transferu w dniu: \" date \"\\"\"
print \"set xrange [0:23]\"
print \"set xtics 1 \"
print \"set xlabel \\"Godziny\\"\"
print \"set ylabel \\"Transfer [MB]\\"\"
print \"set label \\"Calkowity transfer: \" trafficByDate[date] / ( 1024 * 1024 ) \" MB \\" at graph 0.05, 0.95\"
print \"set label \\"Srednio na godzine: \" trafficByDate[date] / ( 1024 * 1024 ) \" MB \\" at graph 0.05, 0.9\"
print \"set style line 1 lt 3 lw 2\"
print \"set output \\"\" outputFileName \"\\"\"
print \"plot \\"-\\" using 1:2 title \\"Transfer\\" with linespoints ls 1\"
getHourArr()
for ( hour in hourArr )
{
printf \"%s\t%d\n\", hour, trafficByDateHour[date \",\" hour] / ( 1024 * 1024 ) | sort
} close(sort)
print \"e\"
}
Wygenerowanie nazwy pliku wyjściowego
(PNG) zrealizowane jest za pomocą dodania przedrostka
\"transfer_\" oraz zamiany znaków ukośnika
na podkreślenia (patrz funkcja gsub):
outputFileName = \"transfer_\" date \".png\";
gsub(\"/\",\"_\", outputFileName);
Sekwencja ustawiająca parametry wykresu
określa typ generowanego wykresu, tytuł, zakres
argumentów, etykiety na osiach:
print \"set terminal png\"
print \"set autoscale\"
print \"set title \\"Statystyki transferu
w dniu: \" date \"\\"\"
print \"set xrange [0:23]\"
print \"set xtics 1 \"
print \"set xlabel \\"Godziny\\"\"
print \"set ylabel \\"Transfer [MB]\\"\"
Przy dodawaniu do wykresu dwóch napisów,
zawierających sumę oraz średnią transferów,
wartości zawarte w tabelach asocjacyjnych
dzielone są przez 1024^2, aby zamienić bajty na
megabajty:
print \"set label \\"Calkowity transfer: \"trafficByDate[date] / ( 1024 * 1024 ) \" MB \\" at graph 0.05, 0.95\"
print \"set label \\"Srednio na godzine: \"trafficByDate[date] / ( 1024 * 1024 ) \" MB \\" at graph 0.05, 0.9\"
Potem następuje określenie stylu linii (cienka
niebieska) oraz wymuszenie przekazywania danych
do pliku o nazwie określonej na początku:
print \"set style line 1 lt 3 lw 2\"
print \"set output \\"\" outputFileName \"\\"\"
W trakcie funkcji zdefiniowanej stylem numer
jeden (ls 1), łączącej punkty liniami (linespoints)
o nazwie \"Transfer\", argumenty i wartości odczytywane
są z konsoli linia po linii (element \"-\"), aż do
napotkania symbolu \"e\". Atrybut using oznacza,
że argumenty znajdują się w pierwszej kolumnie
danych, a wartości w drugiej:
print \"plot \\"-\\" using 1:2 title\\"Transfer\\" with linespoints ls 1\"
Wygenerowanie tablicy asocjacyjnej \"hourArr\"
zawierającej godziny od 0 do 23 odbywa się
w następujący sposób:
getHourArr()
Natomiast rozpoczęcie iteracji po wszystkich
elementach tablicy, w kolejności rosnącej (patrz
sort):
for ( hour in hourArr )
{
Na koniec pozostaje już tylko wyświetlenie
danych zapisanych w tablicy asocjacyjnej na
podstawie klucza złożonego z daty (podanej jako
argument) oraz godziny (będącej zmienną iteracyjną).
Dane przedstawione są w postaci: godzina \\t
wartość_transferu
printf \"%s\t%d\n\", hour,trafficByDateHour[date \",\" hour] / ( 1024 * 1024 ) | sort } close(sort)
Skrypt kończy się poinformowaniem GnuPlota
o zakończeniu sekwencji danych:
print \"e\"
}
Jak łatwo zauważyć, napisany do tej pory kod
skryptu nie jest kompletny. Brakuje mu początku
oraz zakończenia. Większość pracy została jednak
wykonana, a dodanie odpowiednich wywołań
powinno być zwykłą formalnością.
W sekcji BEGIN należy kolejno dodać definicję
separatora pól oraz polecenia powłoki sort:
#!/usr/bin/awk -f
BEGIN {
FS=\" \"
sort=\"sort -k 1nr\"
}
Po analizie danych dokonanej w sekcji wzorzec-
-akcja i na zakończenie działania skryptu należy
wykonać funkcję gnuplotDailyTransfer. Argumentem,
jaki przyjmuje funkcja, jest data, dla której
generowany jest wykres.
Jeśli chcemy, aby skrypt wykonywał funkcję
tylko dla bieżącej daty, to najlepiej jest pobrać ją za
pomocą komendy systemowej date. Odpowiedni
format można nadać za pomocą parametru \"+%d/
%b/%Y\", tak aby zgadzał się z wpisami przechowywanymi
w logach Apache (DD/MMM/YYYY).
Dzięki poleceniu getline można w łatwy sposób pobrać
wynik wykonania komendy i zapisać go w zmiennej
\"currentDate\". Kod ostatniej części skryptu
prezentuje się więc następująco:
END {
\"date \\"+%d/%b/%Y\\"\" | getline
currentDate
gnuplotDailyTransfer(currentDate)
}
AWK - przydatne informacje
Poznane do tej pory właściwości języka AWK
pozwalają na tworzenie prostych skryptów, które
nie wymagają używania dodatkowych operacji na
łańcuchach znaków lub zmiennych. W tej części
artykułu przedstawione zostaną najważniejsze
koncepcje języka AWK wzbogacone prostymi
przykładami.
Zmienne
W języku AWK wszystkie zmienne mają charakter
globalny. Nieważne, czy są zadeklarowane
w funkcji, czy wewnątrz sekcji BEGIN. Zawsze dostępne
są z dowolnego miejsca w kodzie. Jedynym
wyjątkiem jest zmienna przekazana jako argument
funkcji - dostęp do niej ograniczony jest tylko do
ciała funkcji.
Podobnie jak w wielu językach skryptowych,
zmienne w AWK nie mają typów. Oznacza to, że
można przypisać do nich praktycznie dowolną wartość
bez jawnego deklarowania typu zmiennych.
Tak naprawdę sama deklaracja zmiennej następuje
dopiero w momencie jej użycia. Przykładowo:
zmienna1 = 0
zmienna2 = \"jakis tekst\"
zmienna3 = \"wc -l\"
Pierwsza i druga deklaracja definiują kolejno
zmienną niejawnego typu całkowitego oraz
znakowego. W ostatnim wariancie zmienna ma
charakter znakowy, ale w zasadzie jest poleceniem
powłoki, które może zostać wykonane w momencie
jej użycia.
Łańcuchy znaków
AWK ma bogaty zbiór operacji przeprowadzanych
na łańcuchach znaków. Najprostszą z nich
jest konkatenacja, czyli łączenie dwóch łańcuchów
w jeden. Można jej dokonać za pomocą następującej
notacji:
\"łańcuch pierwszy\" \"łańcuch doklejony\".
Niewymagany jest tutaj operator plusa lub
kropki tak jak w przypadku PHP lub Javy.
Ponadto warto wymienić również inne funkcje
pozwalające na bardziej zaawansowane modyfikacje
stringów. Najbardziej popularne i te użyte
w dalszej części artykułu przedstawione są poniżej:
- index(in, find) - funkcja zwracająca pozycję
wystąpienia słowa lub wyrażenia \"find\" wewnątrz
łańcucha \"in\". Gdy łańcuch nie zostanie
dopasowany, zwracana jest wartość zero.
Przykładowo: index(\"tomek\", \"ek) zwróci wartość 4. - length(string) - zwraca liczbę znaków w łańcuchu
\"string\". - split(string, array, fieldsep) - dzieli łańcuch
znaków \"string\" według separatora określonego
w zmiennej \"fieldsep\". Warto wspomnieć
o tym, że element dzielący może być zarówno
stringiem, jak i wyrażeniem regularnym. Elementy
podzielonego łańcucha zapisane zostają
w tablicy \"array\". - gsub(regexp, replacement, target) - zamienia
wszystkie wystąpienia wzorca \"regexp\" w łańcuchu
\"target\" na te określone w \"replacement\". - substr(string, start, length) - wycina z łańcucha
\"string\" wszystkie znaki od pozycji \"start\", aż do
długości określonej przez \"length\".
Wykonywanie poleceń powłoki
Czasami zmuszeni jesteśmy wykonać polecenie
powłoki i przekazać jego wynik do wybranej
zmiennej. Można to zrobić dzięki zastosowaniu
konstrukcji:
\"polecenie\" getline nazwa_zmiennej
Przykładowo: \"wc -l plik.txt\" getline iloscLinii,
zapisze do zmiennej iloscLinii wynik wykonania
polecenia word count.
Możliwość stosowania komend powłoki przydaje
się również podczas sortowania danych zawartych
w tabelach lub listach. Najczęściej stosuje
się wtedy specjalną konstrukcję, taką jak poniżej:
sort=\"sort -k 1nr\"
for ( element in Tablica )
{
print element | sort
} close(sort)
Zmienna \"sort\" wykorzystana jest do przechowania
polecenia powłoki odpowiedzialnego
za sortowanie danych. Parametry przekazane do
polecenia wymuszają sortowanie leksykograficzne,
uwzględniając pierwsze pole łańcucha znaków.
Zadaniem pętli for jest przejście po wszystkich elementach
tablicy z jednoczesnym przekazaniem aktualnego
elementu do polecenia sort. Właściwy proces
sortowania odbywa się jednak dopiero przy wyjściu
z pętli podczas wykonania instrukcji close(sort).
GnuPlot, z czym to się je?
GnuPlot to konsolowa aplikacja działająca
w środowisku linuksowym, służąca do generowania
zaawansowanych wykresów graficznych
2D i 3D. Aplikacja działa w trybie interaktywnym
oraz wsadowym. W tym ostatnim przyjmuje na
wejście odpowiednio przygotowany plik z danymi
źródłowymi, na którego podstawie generowany
jest wykres.
Dużą zaletą GnuPlota jest możliwość zapisywania
wykresu do wielu formatów graficznych
(wektorowych oraz rastrowych). Uzyskane w ten
sposób rysunki wyglądają profesjonalnie, a ich
jakość zadowoli niejednego grafika.
Przykładowa składnia pliku wsadowego
GnuPlota może wyglądać tak jak na listingu 2.
GnuPlota (wykres.gp)
set terminal postscript eps color
set autoscale
set title \"Przykladowy tytul\"
set xrange [0:2]
set xtics 1
set xlabel \"Argumenty\"
set ylabel \"Wartosci\"
set style line 1 lt 1 lw 4
set output \"plik.eps\"
plot \"-\" using 1:2 title \"Funkcja\" with
lines ls 1
2 10
1 5
0 0
e
Przyjrzyjmy się jej dokładnie. Najpierw ma miejsce
definicja rodzaju pliku wyjściowego:
set terminal postscript eps color
set autoscale
Potem ustawienie tytułu wykresu:
set title \"Przykladowy tytul\"
Podanie zakresu argumentów - przedział
obustronnie domknięty:
set xrange [0:2]
set xtics 1
Etykiety na osiach X oraz Y:
set xlabel \"Argumenty\"
set ylabel \"Wartosci\"
set style line 1 lt 1 lw 4
Wskazanie pliku, do którego zostanie zapisany
wykres:
set output \"plik.eps\"
Polecenie, aby program narysował wykres na
podstawie danych zawartych poniżej. Opcja \"-\"
oznacza odczytanie danych wejściowych z konsoli.
Dzięki właściwości using możliwe jest wskazanie
kolumn, z których pobierane są dane:
plot \"-\" using 1:2 title \"Funkcja\" with lines ls 1
Podanie danych potrzebnych do wygenerowania
wykresu według kolejności: argument, wartość.
Zakończenie danych znakiem \"e\":
2 10
1 5
0 0
e
Wykonanie polecenia: gnuplot wykres.gp spowoduje
wygenerowanie pliku EPS zawierającego
wykres funkcji liniowej przedstawionej na rysunku.