Pokazywanie postów oznaczonych etykietą unix. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą unix. Pokaż wszystkie posty

poniedziałek, 16 lutego 2009

Skrzynka z narzędziami

Podczas pracy z plikami tekstowymi często powstaje potrzeba przeprowadzenia prostej operacji w rodzaju sortowania, zmiany kolejności, sumowania itp. Zwykle odruchem jest pisanie jednolinijkowca w AWK-u albo innym ulubionym języku. Niesłusznie. Czasem lepiej jest otworzyć skrzynkę z narzędziami i poszukać gotowca. W Unix-ie mamy mnóstwo małych gotowych programów. Zdarzyło mi się napisać program, który robił to, co shuf i inny, który wykonywał operację paste. Niepotrzebnie. Poniżej wymieniam kilka z tych narzędzi.

csplit:podział pliku na podstawie zawartości
cut:wybranie kolumn
join:połączenie plików wg wspólnej kolumny
paste:sklejenie plików kolumnami
shuf:mieszanie kolejności linii w pliku
split:podział pliku na równe kawałki
tac:wypisanie pliku liniami od tyłu
tr:zamiana znaków
uniq:wybranie linii powtarzających się

Warto zapoznać się z nimi - mają bogaty repertuar różnych opcji - na przykład program split może zliczać linie, albo znaki. Program paste może skleić pliki pionowo lub poziomo. Program shuf może mieszać linie, ale może też potasować swoje argumenty. I tak dalej. Skrzynka narzędziowa jest pełna !

Jednolinijkowce w AWK-u

AWK jest językiem programowania nadającym się wybitnie do tworzenia jednolinijkowców. "Jednolinijkowiec" to skrypt napisany ad-hoc, bez edytora, od razu w linii komend. Często mieści się w jednej linii - stąd nazwa.

Pracując nad analizą techniczną kursów walut używam często awk-a i bash-a jako narzędzi szybkiego prototypowania i błyskawicznych kalkulacji.

Przykład: w pliku A.txt mam dane w postaci tekstowej, każda linijka zawiera jedną liczbę - wartość kursu w danym punkcie. Chcę obliczyć średnią wykładniczą z dziesięciu okresów.

Za pomocą jednolinijkowca w AWK-u robię to tak:

awk '{s=0.1*$1+0.9*s; print s}' A.txt

Po przeczytaniu tego artykułu też będziesz to umieć.

Przykład innego typu: Chcę z pliku B.txt wybrać co dziesiątą linię:

awk '{n++; if(n>=10) {print; n=0}}' B.txt

Przykład trzeci - powiedzmy, że w pliku C.txt mam dwie kolumny z wartościami liczbowymi. Chcę obliczyć średnią wartość liczb w obu kolumnach. Posługuję się więc jednolinijkowcem, który tworzę w locie:

awk '{p+=$1; x+=$2; n++} END {print p/n, x/n}' C.txt

I tak dalej, wszysto szybko, łatwo i bezbłędnie.

AWK jest genialnie dostosowany do takich celów - ma kilka konstrukcji składniowych, kilka funkcji i kilka reguł, które trzeba poznać, podręcznik mieści się w jednym manualu systemowym, a możliwości są ogromne. Nie ma obiektów, klas, wyjątków ani modułów, ale robi to, co potrzebne. Aby sobie to uzmysłowić, wystarczy zrozumieć, jak działa AWK.

DZIAŁANIE AWK-a

Program w AWK-u to lista reguł. Każda reguła to wzorzec i akcja. Program czyta dane rekord po rekordzie, znajduje pierwszy wzorzec, który może być dopasowany do rekordu i wykonuje skojarzoną z nim akcję. Rekord dzieli się na pola, oznaczane w akcjach i wzorcach symbolami $1, $2, $3 itd.

Przykład:

awk '$1>1 {n++} END {print n}'

awk - to komenda - nazwa programu awk '$1>1 {n++} END {print n}' - to program w AWK-u, składa się z dwóch reguł: $1>1 {n++} - wzorzec $1>1 oznacza rekordy, w których wartość numeryczna pierwszego pola jest większa niż 1, akcja {n++} oznacza inkrementację zmiennej n END {print n} - wzorzec END to sztuczny wzorzec, nie dopasowywany do żadnego rekordu, skojarzona z nim akcja wykonywana jest na zakończenie programu. W tym wypadku wypisuje liczbę n.

Powyższy program liczy linie, w których pierwsza kolumna zawiera liczbę większą od 1, a następnie wypisuje wynik.

Akcje ujęte są w nawiasy {}, warunki to wyrażenia relacyjne lub specjalne symbole BEGIN lub END.

Inny przykład - pomnożenie wszystkich liczb zawartych w pliku:

awk 'BEGIN {x=1} {x*=$1} END {print x}'

Aby zmusić program do zainicjowania zmiennej jedynką został tu użyty wzorzec BEGIN. Tyle informacji wystarczy, aby rozpocząć eksperymentowanie.

środa, 1 października 2008

Post Scriptum i PostScript

Mój dobry znajomy opublikował niedawno nowe narzędzie do generowania PostScriptu. Jest to proceduralny język programowania o składni zbliżonej do C, tłumaczony bezpośrednio na PostScript - nazywa się Post Scriptum. Angielskie słowo "postscript" znaczy to samo, co łacińskie (czy też międzynarodowe) - "post scriptum". Aby zrozumieć możliwe zastosowania Post Scriptum, należy po pierwsze wiedzieć jak działa i czym jest PostScript. Potocznie traktowany jako format plików graficznych, w rzeczywistości PostScript jest językiem programowania wysokiego poziomu, stworzonym jako język opisu strony (page description language), ale będącym pełnym językiem programowania. PostScript jest idealny do generowania maszynowego, niezbyt jednak nadaje się do użycia ręcznego. Problemem jest przede wszystkim składnia języka, oparta na odwrotnej notacji polskiej (Reverse Polish notation) pozbawiona nawiasów. Predestynuje ona PostScript do generowania automatycznego, ale praktycznie uniemożliwia żywemu programiście szybkie czytanie złożonego kodu. Oto przykład: Wyrażenie w Post Scriptum, zrozumiałe dla każdego programisty:
if (x[1] > 2*y) 
    x[1]=y-1; 
else 
    x[1] += 1;
zapisane w PostScripcie wygląda na przykład tak:
x 1 get 2 y mul gt{
   x 1 y 1 sub put
}
{
   x 1 x 1 get 1 add put
} ifelse
Na tym poziomie da się to jeszcze czytać przy odrobinie wprawy, ale już widzimy różnicę - musimy się trochę skupić. W bardziej złożonych programach wyszukanie błędu jest mozolne i naprawdę można tego uniknąć używając Post Scriptum. Taka beznawiasowa składnia nazywana jest postfiksową - tak nazywa się zapis, w którym argumenty stoją przed operatorami - stąd chyba zresztą wzięła się nazwa PostScriptu. Autor Post Scriptum celnie zauważył, że składnia ta jest jedynym elementem języka, który powstrzymuje programistów od masowego bezpośredniego używania PostScriptu. Pozostałe elementy języka, takie jak zarządzanie pamięcią, system typów, czy wreszczie rozbudowany system graficzny, stanowiący clue PostScriptu, są wygodne, przemyślane i dopracowane - można powiedzieć, że aż chciałoby się ich używać, gdyby nie ten język ... Wniosek był jeden: trzeba stworzyć język, który będzie miał klasyczną składnię, a tłumaczony będzie na PostScript. Tak powstało Post Scriptum. Podobnie powstał język C - w wyniku znużenia zawiłościami kodu assemblerowego. Ale można w C zakodować prawie wszystko to, co w asemblerze. Podobnie w naszym nowym języku - program w Post Scriptum może być funkcjonalnie równoważny dowolnemu programowi w PostScripcie. Nowy język posiada klasyczne konstrukcje sterujące: pętle, instrukcje "if", funkcje. Obsługuje typy danych PostScriptu: słowniki (odpowiedniki paskalowych rekordów, struktur C, czy PHP-owych hashów), stringi i oczywiście liczby stało- i zmiennoprzecinkowe. Operatory PostScriptu udokumentowane bardzo dokładnie w "PostScript Language Reference Manual" firmy Adobe) są wywoływane bezpośrednio jak każda inna funkcja, dzięki czemu Post Scriptum daje dostęp do całej graficznej maszynerii PostScriptu. Możliwe jest też włączanie kodu napisanego w PostScripcie bezpośrednio do programu w Post Scriptum. Na etapie kompilacji można dołączać fragmenty kodu (klasyczna dyrektywa "include") jak i gotowe fragmenty PostScriptu (dyrektywa "import"). Autor poprzedził pracę nad tym językiem poszukiwaniami gotowego rozwiązania tego typu i - o dziwo - nie znalazł. W dalszych planach, o ile mi wiadomo, jest wsparcie dla kontroli typów (obecnie język jest polimorficzny, jak PostScript), kontrola prototypów funkcji i inne feature'y wspierające szybkie tworzenie i debugowanie kodu. Życzę autorowi dalszego zapału i zachęcam wszystkich do odwiedzenia strony "Post Scriptum".

czwartek, 19 czerwca 2008

Najprostsze pliki graficzne

Trzy formaty plików graficznych: PPM, PGM i PBM (portable pixmap, portable graymap, portable bitmap) wspólnie określane popularnie jako "portable anymap" stanowią w zamyśle autorów "wspólny mianownik" formatów graficznych, format prosty i oczywisty, pozwalający na wymianę danych graficznych pomiędzy systemami i programami. Format zdefiniowany w latach 80-tych i używany do dziś.

Wszystkie trzy oparte są na wspólnej zasadzie: plik zawiera nagłówek z koniecznymi danymi (rozmar, typ) i prostokątną macierz pixeli. Pixel określa kolor w postaci składowych RGB (dla pixmap PPM), stopień szarości (dla greymap) lub jednobitową wartość biało-czarną (dla bitmap). Format zdefiniowano w wariancie binarnym i tekstowym. W przyrodzie występują z rozszerzeniem .ppm, .pbm i .pgm, ale także .pnm (Portable aNyMap).

Dalszym rozwinięciem tego formatu jest PAM, występujący tylko w formie binarnej, pozwalający na dalsze rozszerzenia, kanał alfa itp.

W Twoim Unixie znajdziesz mnóstwo programów - narzędzi zawierających w nazwie ciąg znaków ppm, pnm, pgm itp. Oto rezultat komendy "apropos pnm" na komputerze, na którym piszę ten artykuł (pierwszy fragment) :

anytopnm (1)         - attempt to convert an unknown type of image file to a portable anymap
bmptopnm (1)         - convert a BMP file into a portable anymap
calibrate_ppa (8)    - pnm2ppa calibration tool
fiascotopnm (1)      - Convert compressed FIASCO image to PGM, or PPM
fitstopnm (1)        - convert a FITS file into a portable anymap
gemtopnm (1)         - convert a GEM .img file into a portable anymap
giftopnm (1)         - convert a GIF file into a portable anymap
jpegtopnm (1)        - convert JPEG/JFIF file to portable pixmap or graymap
palmtopnm (1)        - convert a Palm pixmap into a portable anymap
pamdeinterlace (1)   - remove ever other row from a PAM/PNM image
pamfile (1)          - describe a Netpbm (PAM or PNM) file
pamstretch (1)       - scale up a PNM or PAM image by interpolating
between pixels
pamstretch-gen (1) - use pamstretch and pnmscale to scale by non-integer values pngtopnm (1) - convert a Portable Network Graphics file into portable anymap pnm2ppa (1) - convert portable anymap (PNM) images to HP's
PPA printer format. pnmalias (1) - antialias a portable anyumap. pnmarith (1) - perform arithmetic on two portable anymaps pnmcat (1) - concatenate portable anymaps pnmcolormap (1) - create quantization color map for a portable anymap pnmcomp (1) - composite (overlay) two portable anymap files together pnmconvol (1) - general MxN convolution on a portable anymap pnmcrop (1) - crop a portable anymap pnmcut (1) - cut a rectangle out of a portable anymap pnmdepth (1) - change the maxval in a portable anymap pnmenlarge (1) - read a portable anymap and enlarge it N times pnmfile (1) - describe a portable anymap pnmflip (1) - perform one or more flip operations on a portable anymap pnmgamma (1) - perform gamma correction on a portable anymap pnmhisteq (1) - histogram equalise a portable anymap pnmhistmap (1) - draw a histogram for a PGM or PPM file pnmindex (1) - build a visual index of a bunch of anymaps pnminterp (1) - scale up a PNM or PAM image by interpolating between pixels pnminterp-gen (1) - use pamstretch and pnmscale to scale by non-integer values pnminvert (1) - invert a portable anymap pnmmargin (1) - add a border to a portable anymap pnmmontage (1) - create a montage of portable anymaps pnmnlfilt (1) - non-linear filters: smooth, alpha trim mean, optimal estimation smoothing, edge enhancement.
.......

Biorąc pod uwagę, że każdy taki plik można zamienić na postać tekstową, którą łatwo przetwarzać przy użyciu narzędzi typu awk/perl/bash/sed, mamy w ręce pełną bibliotekę graficzną ...

poniedziałek, 16 czerwca 2008

OOA/OOD i Air Traffic Control

Metoda obiektowa projektowania i analizy software'u ma w opinii zwolenników wprowadzić dyscyplinę i porządek do procesu tworzenia oprogramowania. W rzeczywistości wydaje się być jednak za mało ścisła. W klasycznych książkach Coada i Yourdona i na wykładach w uczelniach technicznych, które opierają się na tej obiektowej tradycji proponuje się poszukiwanie klas i obiektów w fizycznej rzeczywistości i odwzorowanie ich w projekcie. Zawsze mnie to dziwiło, jakim cudem struktura rzeczywistości ma się tak prosto przenieść na strukturę programu. Ma to sens, owszem, ale tylko w symulacji komputerowej. Należy zawsze pamiętać o tym, że obiekty w programie to odwzorowanie naszej wiedzy, a nie stanu rzeczywistego obiektu. I tak, na przykład, w programie używanym w aptece, owszem, mamy obiekt klasy "pacjent" a także "lekarstwo", ale nie będzie metody "pacjent.zażyj( lekarstwo )", bo to tylko w rzeczywistości pacjenci zażywają lekarstwa. W komputerze nie.

W książce Coada i Yourdona autorzy posługują się przykładem wziętym z życia: systemem kontroli ruchu powietrznego. Pełno tam tras, radarów i samolotów. Kiedy to czytałem, nie wiedziałem, dlaczego akurat te radary są takie ważne. Potem, parę lat później, przypadkowo natrafiłem na klasyczną unixową grę tekstową atc. Był to prosty symulator konsoli radaru kontrolera ruchu powietrznego. Na ekranie powyżej widzimy, jak to działa. Właśnie w mój obszar wleciały dwa samoloty: b7 i A7. A7 zmierza w stronę wyjścia E1, a b7 w stronę E4 (widzimy ten "plan lotu" w tabelce po prawej). Oba znajdują się na wysokości 7 tys. stóp (oznacza to siódemka w symbolu samolotu). Należy, wydając odpowiednie komendy dotyczące kierunku ruchu i wysokości lotu doprowadzić wszystkie samoloty do ich przeznaczenia i nie dopuścić do zderzenia. Po kilkunastu minutach konsola radaru zawiera kilka lub kilkanaście samolotów, a człowiek jest znużony z powodu ciągłego napięcia. Ponieważ sterowanie wyimaginowanymi samolotami jest bardzo zajmujące, postarałem się o zdobycie bardziej rozbudowanych, graficznych programów, w końcu zacząłem używać darmowego symulatora firmy Xavius. Prawdę mówiąc ze wszystkich gier komputerowych, jakie miałem w życiu poznać (cóż poznałem ich niewiele w porównaniu z moimi kolegami) ten rodzaj wciągnął mnie najbardziej. I siedząc godzinami w najwyższym napięciu nad sektorem powietrznym Chicago lub Los Angeles powoli uzyskiwałem wgląd w hierarchię klas Coada i Yourdona dotyczącą dziedziny ruchu powietrznego. Jedno jest pewne: aby zobaczyć te klasy, trzeba choć trochę poznać tematykę, której dotyczy dany projekt. Prymitywna gra atc(6) okazała się bardzo zbliżona w charakterze do tych złożonych. Najwidoczniej jej autor wykonał kawał dobrej analizy obiektowej ...

czwartek, 5 czerwca 2008

Widzenie barwne i Unix

Widzenie barwne człowieka oparte jest na trzech różnych typach komórek światłoczułych, czułych odpowiednio na światło czerwone, zielone i niebieskie, dlatego każde wrażenie barwne może być wywołane za pomocą bodźców trójkolorowych wymieszanych w odpowiednich proporcjach. Kolor żółty widzimy, gdy pobudzimy oko mieszaniną barwy zielonej i czerwonej, ale identyczny kolor spostrzegamy gdy pobudzimy oko monochromatycznym światłem żółtym. Nie ma tu analogii do słyszenia dźwięków: człowiek odróżnia wielodźwięki od dźwięków prostych, ponadto nie jest wrażliwy na wysokość dźwięku, a raczej na ich różnicę.

Znalazłem gdzieś w sieci obrazek mający przedstawiać widmo światła białego:


Postanowiłem zbadać, jak został skonstruowany z trzech barw
składowych. Tęcza powinna składać się z barw prostych o zmieniającej się płynnie długości. Grafika komputerowa to - wiadomo - mieszanina trzech barw prostych o różnym natężeniu w różnych punktach - coś całkiem innego niż oryginalny pierwowzór. Gdyby istniała istota zdolna do widzenia absolutnego barw, bez trudu rozpoznałaby oszustwo. Ja potrzebowałem do tego kilku narzędzi uniksowych.

Po pierwsze rozkompresowałem obrazek przy użyciu djpeg:

$ djpeg pasek.jpg > pasek.ppm

Następnie przekonwertowałem plik na format tekstowego ppm'a, aby łatwiej mi było go dalej przetwarzać:

$ pnmnoraw pasek.ppm > pasek.txt
Szybki rzut oka do pliku:

$ head pasek.txt
P3
600 66
255
254 0 0
254 0 0
254 0 0  
254 0 0  
253 1 0  
....

Mamy 600 pikseli szerokości.

Teraz zamieniam trochę porządek, żeby mieć jeden piksel w jednym wierszu:

$ awk '{
>         S="";
>         for (i=1; i<=NF; i++) {
>                 S=S" "$i;
>                 if (i % 3 == 0) {
>                         print S;
>                         S="";
>                 }
>         }
> }' pasek.txt > pasek.x

$ head pasek.x
254 0 0
254 0 0
254 0 0
254 0 0
....
Dobrze idzie, teraz wezmę jeden rządek i narysuję wykres nasycenia trzech barw:
 
$ head -n 600 pasek.x > pasek3
$ gnuplot
gnuplot> plot 'pasek3' using 1 with lines, 'pasek3' using 2 with
lines, 'pasek3' using 3 with lines
Pięknie, widać, co zrobił autor tego rysunku: wygenerował go automatycznie używając kawałków liniowych funkcji !

Jeszcze tylko wykonałem zrzut ekranu i zamieniłem go na jpg, żeby umieścić wykres w blogu:

 
$ xwd
$ xwdtopnm pasek.xwd > pasek3.ppm
xwdtopnm: writing PPM file
$ cjpeg pasek3.ppm > wykres1.jpg
Gotowe.
Ciekawe, jakbym to zrobił w Windowsach ...

Ciekawostką jest fakt, że gnuplot do oznaczania kolejnych linii używa kolorów właśnie w kolejności
czerwony, zielony, niebieski.
Inną ciekawostką jest czerwony składnik po prawej stronie widma -
tam, gdzie mamy mocny fiolet.

piątek, 6 lipca 2007

TargetWriter

Jak napisać generator tekstu oparty na szablonach ? Nie trzeba go pisać - istnieje i jest bardzo znany, to BASH. Wystarczy napisać kilka funkcji i korzystając z mechanizmów basha można generować dowolny tekst. Tak powstał WriteTarget, generator oparty na bashu. A tak wygląda próbka kodu:
# the template hello.tpl:
cat <<END_OF_FILE
<html>
<head>
     <title> $(target MAIN_TITLE) </title>

</head>
<body>
     <h1> $(target MAIN_TITLE) <h1>
     $(target TEXT)

</body>
</html>  
END_OF_FILE 

# the text file:
. ./hello.tpl

write MAIN_TITLE  H E L L O
write TEXT Hello world !