Any tool should be useful in the expected way, but a truly great tool lends itself to uses you never expected.
Każde narzędzie powinno być użyteczne w przewidziany sposób, jednak naprawdę wielkie narzędzie znajduje nieprzewidziane zastosowania.
Eric S. Raymond, The Cathedral and the Bazaar (Katedra i bazar) (1997)more
i less
: drukowanie zawartości pliku na terminalugrep
: wyszukiwanie wzorca w plikucat
i type
: wysyłanie zawartości plików na wyjściesplit
: dzielenie dużego pliku na częścihead
i tail
: pobieranie wierszy początkowych i końcowych z plikówcut
i paste
: zarządzanie kolumnami plików znakowychsed
: edytor automatycznytr
: automatyczny translator znakówsort
: sortowanie danych w plikuuniq
: usuwanie powtarzających się wyrazów z ciągu danychDobrze zaprojektowany system operacyjny powinien posiadać zestaw programów narzędziowych, które operują na danych zapisanych w plikach znakowych przekształcając je w ściśle określony sposób, z pozostawieniem użytkownikowi decyzji co do sposobu wykorzystania danych wynikowych. Zestaw takich narzędzi można więc przyrównać do warsztatu wyposażonego w śrubokręty, klucze nasadowe czy szczypce, które każdy może wykorzystać do realizacji swoich szczególnych celów w sposób, jaki uzna za stosowny. Znajomość zasad korzystania z narzędzi umożliwia ich twórcze wykorzystanie przy realizacji nowych zadań.
Przedstawione w tym rozdziale uwagi dotyczące zasad uruchamiania programów oraz sterowania wejściem i wyjściem odnoszą się do wszystkich systemów operacyjnych typu DOS, MacOS, UNIX i Windows, a także do kilku innych grup systemów.
Przy omawianiu filtrowania plików znakowych skupiono się na filtrach opracowanych dla systemu UNIX, ponieważ stanowią absolutną klasykę i tworzą spójny zestaw silnych narzędzi. Z zestawu tego korzystać mogą użytkownicy wszystkich współczesnych systemów operacyjnych. Nie jest jednak wykluczone, że poszczególne prace da się wykonać także za pomocą nieco innych narzędzi zależnych od systemu operacyjnego używanego akurat przez czytelnika.
Spośród omawianych niżej programów, more
i sort
są standardowymi elementami wszystkich wspomnianych systemów;
programy cat
, cut
, head
, tail
, join
,
split
,
paste
, grep
, sed
, tr
, xargs
, uniq
i comm
są elementami systemów UNIX i GNU,
w systemach DOS i Windows można je
zainstalować; program less
jest poleceniem systemu GNU,
w innych systemach można go zainstalować;
polecenie type
jest odpowiednikiem UNIXowego
programu cat
w systemach DOS i Windows.
Sekwencyjny procesor poleceń (shell) to program, udostępniający
wiersz poleceń i przejmujący kontrolę nad poleceniami wydawanym przez
użytkownika. Polecenie składa się z komendy i jej parametrów, rozdzielonych
spacjami. Każdy procesor poleceń rozpoznaje pewien ograniczony zbiór komend
dotyczących głównie zarządzania systemem plików i własnej konfiguracji.
Są to tzw. komendy wewnętrzne. Inne polecenia, zwane zewnętrznymi, są
traktowane jak nazwy programów, które należy uruchomić. Według ogólnie
obowiązującej zasady polecenie zewnętrzne jest nazwą pliku
wykonywalnego tego programu.
Plik wykonywalny jest wyszukiwany w systemie plików kolejno w katalogach
zadanych w konfiguracji systemu jako „ścieżki poszukiwań”.
W systemach DOS/Windows
w pierwszej kolejności sprawdzany jest katalog bieżący.
W systemach UNIX katalog bieżący nie jest
przeszukiwany, chyba że symbol .
został podany jako jedna ze ścieżek poszukiwań.
Po napotkaniu pierwszego pliku wykonywalnego o podanej nazwie
system przerywa wyszukiwanie i uruchamia go.
W prawidłowo skonfigurowanym systemie operacyjnym obszar poszukiwania
powinien obejmować wszystkie katalogi, z których programy mają być
uruchamiane przez podanie krótkiej, a nie pełnej nazwy.
Dane o ścieżkach przechowuje zmienna środowiskowa PATH
,
określana w skryptach konfiguracyjnych.
W systemach DOS i Windows
procesor poleceń nosi nazwę command.com
, cmd.exe
lub powershell.exe
.
W systemach UNIX użytkownik ma do wyboru kilka różnych procesorów
(m.in. sh
, csh
, bash
, ksh
);
oferują one znacznie bogatsze możliwości.
Podczas pracy proces może pobierać i wysyłać dane.
Dla umożliwienia współpracy zarówno z użytkownikiem–osobą,
jak klientem–programem zlecającym wykonanie pewnych czynności,
wiele programów pobiera dane z urządzenia określanego jako
standardowy plik wejściowy. Dane ze standardowego wejścia mogą być
tylko odczytywane po kolei, bez możliwości powrotu do danych już odczytanych.
Jego odpowiednikiem na „drugim końcu” procesu przetwarzania
jest standardowy plik wynikowy, zwany czasami w technicznym żargonie
wyjściem standardowym. Do pliku wynikowego można wyłącznie wpisywać
dane (zwykle wyniki, ale czasem także komunikaty dla użytkownika),
bez możliwości ich odczytania ani modyfikacji po zapisaniu. Proces realizujący polecenie
„nie wie” nic więcej o plikach standardowego wejścia i wyjścia. Domyślnie
pliki te są identyfikowane z konsolą, zwaną inaczej terminalem, tj. zespołem klawiatura–monitor
urządzenia, z którego wywołano program. Dzięki operacji zwanej przekierowaniem
mogą jednak zostać skojarzone z dowolnym plikiem, w tym także ze strumieniem danych wejściowych
lub wynikowych innego procesu. Mechanizm przekierowań umożliwia podjęcie decyzji
o źródle danych w chwili wydawania polecenia, a nie tworzenia programu,
i używania gotowych programów jako części składowych większego projektu.
W systemowym wierszu poleceń do przekierowania standardowego pliku wejściowego
służy operator <
, zaś do przekierowania standardowego pliku wynikowego
— operatory: >
, >>
oraz |
.
dir
(DOS/Windows)
lub ls
(UNIX) drukuje na wyjściu standardowym
spis zawartości kartoteki. Domyślnie wyjście jest skierowane
na monitor konsoli. Każde z poleceń dir > spis.txt
(DOS/Windows)
oraz ls > spis.txt
(UNIX) umieści wydruk w pliku tekstowym
o nazwie spis.txt
.
dir >> spis.txt
dopisze wydruk do poprzedniej zawartości pliku spis.txt
.
fc plik1 plik2
(podobnie jak polecenie diff plik1 plik2
)
drukuje na wyjściu standardowym raport z porównania plików plik1
i plik2
. Polecenie fc plik1 plik2 > wynik
(lub odpowiednio diff plik1 plik2 > wynik
)
spowoduje umieszczenie tego raportu w pliku wynik
.
echo
drukuje na wyjściu standardowym ciągi znaków podane jako argumenty wywołania;
np. polecenie echo dzień dobry
spowoduje wydrukowanie napisu dzień dobry.
Polecenie
echo dzień dobry > powitanie
utworzy plik o nazwie powitanie
,
o nastepującej treści:
dzień dobry
dir | more
lub dir | less
uruchomi
program o nazwie more
(w drugim przypadku less
)
i przekaże na jego wejście standardowe wyniki działania polecenia dir
.
(more
i less
to tzw. filtry stronicujące).
sort
pobierze wszystkie dane z wejścia (aż do
napotkania znacznika końca danych — w systemach Windows
jest to znak specjalny ASCII nr 26; na terminalu generuje go kombinacja
klawiszy Ctrl+Z
— a na wyjściu wydrukuje wszystkie wiersze
z wejścia uporządkowane alfabetycznie.
Filtr to program przekształcający strumień danych wejściowych na strumień danych wynikowych aż do otrzymania informacji o końcu transmisji danych. Ogólny schemat pracy filtra można przedstawić następująco:
start przygotuj się do pracy; dopóki (na wejściu są dane) wykonuj ( czytaj daną z wejścia; przetwórz ją; zapisz przetworzoną daną na wyjściu; ); koniec pracy.
Zasadnicza część pracy filtra jest wykonywana w pętli, kończonej dopiero po przetworzeniu wszystkich danych z wejścia. W dowolnej chwili pracy każdego filtra, w której kończy on przetwarzanie kolejnej porcji danych, prawdziwe jest zdanie:
wszystkie dane znajdujące się w pliku wejściowym od jego początku aż do danej bieżącej zostały już odczytane i przetworzone, a efekt przetwarzania został wysłany na wyjście.
Pracę filtra można zilustrować schematem blokowym widocznym poniżej.
more
i less
: drukowanie na terminalu
Filtrem jest np. program more
. Działa on zgodnie z poniższym opisem.
start dopóki (na wejściu są dane) wykonuj ( pobierz wiersz danych z wejścia standardowego; wydrukuj odczytany wiersz na terminalu jeżeli po ostatnim wstrzymaniu pracy terminal został kompletnie zapełniony, to wstrzymaj pracę i czekaj na znak z klawiatury (nie z wejścia standardowego!), zezwalający na dalsze drukowanie; ); koniec pracy.
Program less
, nazwany przez przekorę w opozycji do more
,
ma podobne przeznaczenie, lecz jest bardziej rozbudowany. Oprócz wstrzymywania wyświetlania
potrafi wiele innych rzeczy, np. przewijać wydruk wstecz lub wyszukiwać żądaną frazę.
(Nie mieści się więc w definicji filtra, gdyż magazynuje wszystkie odczytane dane w pamięci roboczej).
grep
: wyszukiwanie wzorca
Ważnym filtrem jest program o nazwie grep
(ang. General Regular Expressions Printing),
działający z grubsza według schematu:
start odczytaj wzorzec i opcje z wiersza poleceń; dopóki (na wejściu są dane) wykonuj ( pobierz wiersz danych z pliku wejściowego; jeżeli wiersz zawiera wzorzec, to drukuj informację o nim na wyjściu, zgodnie z opcjami wywołania (np. z numerem wiersza); ); drukuj zbiorczą informację o danych zgodnie z opcjami wywołania (np. liczba wystąpień wzorca); koniec pracy.
Na przykład polecenie grep "kartotek" *.*
wydrukuje na wyjściu wiersze
wszystkich plików bieżącej kartoteki, zawierające ciąg znaków „kartotek”.
Polecenie grep "kartotek" *.* > wyniki
nie będzie drukować
danych na terminalu, lecz zapisze je w pliku tekstowym o nazwie wyniki
.
Sposób korzystania z programu grep
jest opisany
w instrukcji użytkownika.
Pliki wejściowe | Wynik poleceniagrep "t" plik1 > plikwynikowy | Wynik poleceniagrep -c "t" plik1 plik2 > plikwynikowy | |||||
---|---|---|---|---|---|---|---|
|
|
|
|
Znajdź w pliku geometra.txt
wszystkie wiersze zawierające informację o punktach.
Informację tę, wraz z numerami wierszy, umieść w pliku punkty.txt
,
wydając polecenie:
grep -n -i punkt geometra.txt > punkty.txt
(Opcja -n
każe drukować numery wierszy.
Opcja -i
każe utożsamiać wielkie i małe litery w treści pliku).
Znajdź w plikach bieżącej kartoteki wszystkie miejsca, w których występuje nazwisko Kowalski.
Nazwisko zawsze piszemy z wielkiej litery, a dalej małymi literami. Odmiany gramatyczne: Kowalskiego, Kowalskiemu, Kowalską mają wspólny rdzeń „Kowalsk”.
grep -n Kowalsk *.* > kowalscy.txt
(Opcja -n
każe drukować numery wierszy).
Oto wydruk pliku kowalscy.txt
, jaki moglibyśmy otrzymać:
ANEKS.HTM:5:w osobie Adama Kowalskiego, dyrektora firmy zarządzającej ANEKS.HTM:56:Kowalskim w dniu 15 marca 1999 roku, ANEKS.HTM:224:mgr inż. Adam Kowalski, INTRO.TXT:112:dyrektora Adama Kowalskiego. Jego zaangażowanie w sprawę INTRO.TXT:135:umowy dały dyr. Kowalskiemu możliwości INTRO.TXT:523:lecz zgodnie z wcześniejszymi ustaleniami p. Adam Kowalski nadal UMOWA.HTM:4:w osobie Adama Kowalskiego, dyrektora firmy zarządzającej UMOWA.HTM:136:mgr inż. Adam Kowalski,
(Zdaje się, że za każdym razem jest mowa o tej samej osobie).
Utwórz spis tabel dokumentu o nazwie opis.html
, zapisanego w języku HTML
.
Do tworzenia tabel służy element table
. Będziemy poszukiwać znacznika
otwierającego ten element, a ściślej — jego początkowej frazy „<table
”.
Nawiasu „>
” zamykającego znacznik nie ujmiemy w poszukiwanej frazie,
by wyniki wyszukiwania zawierały także znaczniki z parametrami, takie jak
„<table align="center">
”,
„<table border="1">
”
czy też „<table class="tabelka">
”.
Do wykonania zadania zastosujemy program grep
.
Z uwagi na to, że nazwy elementów HTML
mogą być pisane małymi lub wielkimi
literami, użyjemy opcji -i
(skrót od Ignore letter case).
Potrzebujemy też numerów wierszy pliku, by móc łatwo zidentyfikować wyszukane tabele
(opcja -n
, ang. line Numbers):
grep -i -n "<table" opis.html > spis-tabel
Wyszukiwana fraza zawiera znak „<
” traktowany w wierszu poleceń
jako rozkaz przekierowania wejścia, więc ujęliśmy ją w cudzysłowy tekstowe.
Oto zawartość wygenerowanego tym sposobem pliku spis-tabel
:
79:<table align="center" border="1"> 204:<table align="center" border="1"> 296:<table align="center" border="1">
Zastosuj tę samą metodę wyszukiwania do znajdowania innych wybranych
elementów (odsyłaczy hipertekstowych, hipertekstowych punktów
zakotwiczenia, osadzonych obrazów, miejsc użycia danego stylu) w posiadanych
przez Ciebie dokumentach HTML
. A jak sprawić, by w spisie tabel
pojawiły się ich tytuły (caption
)?
Utwórz spis treści dokumentu o nazwie opis.html
, zapisanego w języku HTML
.
Wiemy, że nagłówki rozdziałów i podrozdziałów są objęte znacznikami <h1>
,
<h2>
, …, <h6>
. Jeżeli cały tytuł (pod)rozdziału
jest umieszczony w jednym wierszu pliku źródłowego, to mamy pewność, że wszystkie tytuły
znajdziemy, wyszukując wiersze z tymi znacznikami.
Jeżeli znaczniki i tytuł nie mieszczą się w tym samym wierszu pliku źródłowego,
to nici z prostego pomysłu, ale nie do końca. Ja sam staram się przestrzegać
zasady „kod nagłówka w całości w jednym wierszu” choćby po to, by móc
stosować proste narzędzia. Jednak nie martw się: grep
i tak znajdzie
znacznik otwierający, a podczas analizy wyników zauważysz, że tytuł jest niekompletny
(np. bez znacznika zamykającego). Możliwe jednak, że do wyników dostaną się wiersze zawierające
ciągi znaków <h12
lub <h1a
, które nie mają nic wspólnego z poprawnymi znacznikami HTML
.
Zadanie jest o stopień trudniejsze od poprzedniego, ponieważ fraza
<h
jest za krótka (pasuje do niej znacznik <hr
,
który nas nie interesuje), a kolejne poszukiwanie fraz od <h1
do
<h6
skomplikuje pracę, zmuszając do porządkowania wyników.
Z pomocą przychodzą wyrażenia regularne: będziemy poszukiwać wzorca
<hcyfra-od-1-do-6
. Na szczęście grep
rozumie składnię wyrażeń regularnych.
Aby nie zapomnieć o znacznikach pisanych wielkimi literami:
<H1>
— takie też mogą się zdarzyć, gdyż były prawidłowe w starszych wersjach
języka — użyjemy opcji -i
(skrót od Ignore letter case).
Numery wierszy dodamy na wszelki wypadek, gdyby okazało się, że tytuł jest zapisany w więcej
niż jednym wierszu pliku:
grep -i -n "<h[123456]" opis.html > spis_tresci
Podobnie jak w poprzednim przykładzie, wyszukiwana fraza została ujęta w cudzysłowy tekstowe. Oto przykładowa zawartość pliku wynikowego:
14:<h1>Efektywne wykorzystanie poleceń systemowych</h1> 26:<h2>Procesor poleceń</h2> 48:<h2>Wejście i wyjście standardowe</h2> 99:<h2>Filtry</h2> 134:<h3>Programy <code>more</code> i <code>less</code>: drukowanie na terminalu</h3> 151:<h3>Program <code>grep</code>: wyszukiwanie wzorca</h3> 166:<h4>Przykład</h4> 177:<h3>Program <code>sed</code>: edytor automatyczny</h3> 193:<h4>Przykład</h4> 269:<h3>Program <code>sort</code>: sortowanie danych w pliku</h3> 274:<h4>Przykład</h4> 293:<h4>Przykład</h4> 324:<h2>Automatyczne uruchamianie programu z różnymi argumentami: program <code>xargs</code></h2> 348:<h3>Przykład</h3>
Ostatni etap to usunięcie nadmiaru informacji (numery wierszy) i przeformatowanie (np. przekształcenie w listę i wykonanie odsyłaczy hipertekstowych) otrzymanego spisu.
Na zakończenie warto wspomnieć o dwóch pożytecznych opcjach programu grep
:
opcja -c
(ang. Count = policz)
zamiast drukowania wierszy zawierających wzorzec, powoduje wydrukowanie jedynie ich liczby.
Opcja -v
(ang. reVert = odwróć) wymusza drukowanie tych wierszy,
które nie zawierają poszukiwanego wzorca.
Uwaga!
grep
grep
-owi nierówny; poszczególne wersje mogą nieco różnić się
składnią. Może okazać się konieczne poprzedzenie wyszukiwanej frazy opcją -e
(tzn. Expression = wyrażenie).
Zamiast
grep "wyrażenie"
spróbuj wtedy
grep -e "wyrażenie"
,
pozostawiając resztę polecenia bez zmian.
W nowszych wersjach systemów Windows istnieje filtr
findstr
o funkcjonalności zbliżonej do grep
. Działa on
w oparciu o tę samą ideę co grep
, choć różni się od niego składnią
i możliwościami. Opis opcji programu findstr
można wywołać korzystając
z opcji /h
.
type
i cat
: wysyłanie zawartości plików na wyjście
Programy te robią rzecz bardzo prostą, lecz przydatną:
przekazują na wyjście cały plik wejściowy lub wszystkie pliki wymienione
w wierszu poleceń. W tym drugim przypadku plik wynikowy składa się
z następujących po sobie zawartości wielu plików (operacja łączenia pionowego).
Program type
należy do systemu Windows.
Program cat
należy do systemów UNIX i GNU.
Dostępna jest instrukcja użytkowania programu cat
w polskim tłumaczeniu.
Pliki wejściowe | Wynik polecenia cat plik1 plik2 > plikwynikowy | ||||
---|---|---|---|---|---|
|
|
|
split
: dzielenie pliku na części
Operacją odwrotną do łączenia jest jeden za drugim jest krajanie,
czyli podział na kawałki (ang. split).
W efekcie powstaje kilka plików zawierających kolejne odcinki pliku wejściowego.
Operację tę realizuje program narzędziowy o nazwie split
.
Równoważny efekt da się osiągnąć, choć zwykle większym nakładem
pracy operatora, korzystając z techniki
„Zaznacz blok/Zapisz blok do pliku”
w sesji edytora interaktywnego.
Sposób użytkowania programu split
jest opisany w stosownej instrukcji.
Plik wejściowy | Wyniki polecenia split -l4 plik1 wynik | ||||||
---|---|---|---|---|---|---|---|
|
|
|
|
head
i tail
: pobieranie wierszy początkowych i końcowych z plików
Programy te przekazują na wyjście ustaloną liczbę początkowych (head
)
lub końcowych (tail
) wierszy pliku wejściowego.
Ponieważ liczbę wierszy końcowych da się ustalić dopiero po pobraniu całego pliku,
programu tail
nie można uważać w ścisłym sensie za filtr.
Domyślną liczbę wierszy (zazwyczaj 10) zmienia się za pomocą opcji wywołania,
np. tail -25 dane.txt
wydrukuje 25 końcowych wierszy pliku
dane.txt
. Użycie tail
bywa bardzo wygodne
nie tylko w trybie nieinteraktywnym, ale także podczas czytania plików danych,
gdyż jest szybsze od uruchomienia edytora i przewinięcia długiego pliku do końca.
Dostępne są polskojęzyczne instrukcje użytkowania programów head
i tail
.
Pliki wejściowe | Wynik poleceniahead -2 plik* > wyniki | Wynik poleceniatail -2 plik* > wyniki | |||||
---|---|---|---|---|---|---|---|
|
|
|
|
cut
i paste
: zarządzanie kolumnami plików znakowych
Cut (wytnij)
i paste (wklej)
to nazwy dwóch ważnych operacji edycyjnych. Pierwsza polega na pobraniu fragmentu pliku,
a druga na wstawieniu przygotowanego uprzednio fragmentu w danym miejscu pliku.
Operacje te, zaimplementowane w oparciu o schowek systemowy, są standardowymi
funkcjami interaktywnych edytorów plików znakowych i dokumentów.
Filtr cut
i program paste
(który filtrem nie jest,
gdyż działa na dwóch wejściach) służą do nieinteraktywnego przeprowadzania
tych operacji z poziomu tekstowego procesora poleceń.
Program cut
czyta plik wejściowy i wysyła na standardowe wyjście fragmenty jego wierszy.
Operator może sprecyzować, o jakie fragmenty pliku chodzi; zazwyczaj dotyczy to określonych kolumn znaków
(czyli znaków zajmujących tę samą pozycję w kolejnych wierszach) lub kolumn pól danych
(czyli słów rozdzielonych separatorami, zajmujących tę samą pozycję w kolejnych wierszach).
Dostępna jest instrukcja użytkowania programu cut
w polskim tłumaczeniu.
Plik wejściowy | Wynik poleceniacut -f2 plik1 > plikwynikowy | Wynik poleceniacut -c3-4 plik1 > plikwynikowy | |||
---|---|---|---|---|---|
|
|
|
Program paste
działa w pewnym sensie odwrotnie do cut
.
Generuje on plik, którego kolejne wiersze są wynikiem połączenia odpowiednich wierszy
dwóch lub więcej wskazanych plików. Sposób łączenia (np. znak separujący części
pochodzące z różnych plików) zadaje się jako opcję działania. Wyniki są wysyłane
na wyjście standardowe.
Dostępna jest instrukcja użytkowania programu paste
w polskim tłumaczeniu.
Pliki wejściowe | Wynik poleceniapaste plik1 plik2 > plikwynikowy | ||||
---|---|---|---|---|---|
|
|
|
Uzupełnieniem kompletu cut
/paste
jest program join
,
którego działanie polega na wzajemnym dopasowaniu wierszy z dwóch plików wejściowych
według zadanego wzorca. Dane wynikowe są umieszczane na wyjściu standardowym.
Oba pliki muszą być uporządkowane według kolumn zawierających wzorzec.
Operacja ta jest odpowiednikiem bazodanowej operacji join (złącz)
i ma sens w odniesieniu do tabel baz danych przechowywanych w plikach znakowych.
Dostępna jest instrukcja użytkowania programu join
w polskim tłumaczeniu.
Pliki wejściowe | Wynik poleceniajoin -1 1 plik1 -2 1 plik2 > plikwynikowy | Wynik poleceniajoin -a 1 -a 2 -1 1 plik1 -2 1 plik2 > plikwynikowy | |||||
---|---|---|---|---|---|---|---|
|
|
|
|
sed
: edytor automatyczny
Innym ważnym przykładem filtra jest edytor strumieniowy sed
(ang. Stream EDitor),
służący do automatycznego przekształcania zawartości pliku
bez wizualnej kontroli operatora. Pojedyncze zmiany w pliku tekstowym
moglibyśmy z powodzeniem przeprowadzać interaktywnie,
na przykład przy użyciu funkcji wyszukiwania i zamiany edytora znakowego.
Jeżeli jednak musimy zamienić kilkadziesiąt różnych fraz
w kilkunastu plikach kilku kartotek
(i na dodatek robić to regularnie raz w miesiącu),
to edytor strumieniowy może się okazać niezastąpiony.
W przeciwieństwie do edytorów interaktywnych, edytor strumieniowy nie jest wyposażony w menu z przyciskami. Ma on jednak instrukcję użytkowania, którą należy się posługiwać.
Reguły przekształcania tekstu należy opracować przed uruchomieniem edytora i zapisać w pliku sterującym. Następnie można uruchomić edytor poleceniem postaci
sed -f plik-sterujący plik-wejściowy > plik-wynikowy
w którym plik-wejściowy
zawiera tekst poddawany obróbce,
a plik-wynikowy
stanowi nazwę pliku, w którym ma być umieszczony efekt pracy.
W żadnym wypadku nie powinien to być ten sam plik. Nazwę pliku wejściowego wolno pominąć,
wtedy strumień danych będzie odczytywany ze standardowego wejścia.
Znaki cyfr przed i po kropce trzeba wydrukować niezmienione.
Oznaczymy je jako bloki parami komend-nawiasów \(
i \)
.
Blok numer n będzie nosił nazwę \n
:
\([0-9]+\).\([0-9]+\) → \1,\2
czyli w składni poleceń programu sed
s/\([0-9]+\)\.\([0-9]+\)/\1,\2/g
Zastosowanie tej reguły zamiany nie wyrządzi krzywdy kropkom strzegącym końców zdań ani skrótom wyrazów.
Powiedzmy, że mamy do czynienia z plikiem zawierającym tabelę postaci
imię nazwisko data-urodzenia wzrost
i że chcemy w nim zamienić kolejność kolumn pierwszej i drugiej. Elementy kolumn są oddzielane znakami tabulacji. Wpisy do tabeli mogą zawierać znaki liter wielkich i mały, znaki cyfr, znaki przestankowe (kreski poziome, ukośniki, kropki) i spacje. Dla uproszczenia przyjmiemy, że w tabeli używano tylko liter łacińskich. Zdefiniujemy wyrażenie regularne, w którym wyróżnimy następujące elementy:
\([a-zA-Z\. \-]*\)
;
pierwsza wyróżniona grupa znaków otrzymuje nazwę \1
;\t
;\([a-zA-Z\-\. ]*\)
; druga wyróżniona grupa znaków
otrzymuje nazwę \2
;\t
;\([a-zA-Z0-9\.,:;\/ \?\t=-]*\)
. Budowa wewnętrzna tych danych
nas nie interesuje, gdyż będziemy ją traktować jako niepodzielną całość;
trzecia wyróżniona grupa znaków otrzymuje nazwę \3
;$
.Każdy prawidłowo zbudowany wiersz naszego pliku bazy danych jest wyrażeniem o podanej wyżej postaci. Należy go przekształcić do postaci:
nazwisko imię data-urodzenia wzrost
którą możemy opisać za pomocą wyrażenia zastępującego
\2\t\1\t\3
Zatem odpowiedniej regule dla edytora strumieniowego można nadać postać:
s/\([a-zA-Z .\-]*\)\t\([a-zA-Z \.\-]*\)\t\([a-zA-Z0-9 \.,:;\/\?\t=\-]*\)$/\2\t\1\t\3/g
Oto gotowy plik reguł.
Przypomnijmy sobie podstawowe reguły automatycznej poprawy interpunkcji:
([{
),)]}
)
lub interpunkcyjnym (dowolnym spośród .,;:!?
),I już mamy gotowy plik reguł (przemyśl kolejność stosowania reguł; jest ona bardzo istotna). Działa? zobacz w takim razie, co się stanie z liczbą dziesiętną, taką jak 1.22 lub 1,234. Co proponujesz?
Dobrym przykładem poważnego zastosowania edytora strumieniowego jest wykonanie
hipertekstowego spisu zawartości kartoteki, w którym nazwy wszystkich
plików źródłowych HTML
z danej kartoteki i jej podkartotek
winny być objęte odsyłaczami do tych właśnie plików.
Polecenie dir /s/b *.* > spis.txt
(DOS/Windows)
lub find * > spis.txt
(UNIX)
wydrukuje na wyjściu spis zawartości kartoteki
wraz z podkartotekami i umieści go w pliku znakowym spis.txt
.
Pojedynczy wiersz tego pliku będzie miał postać
ścieżka\plik.roz
Zastosujmy edytor sed
wydając polecenie
sed -f reguly spis.txt > spis.htm
które spowoduje, że program ten odczyta reguły zamiany z pliku reguly
, zastosuje je do treści pliku
spis.txt
i zapisze zmodyfikowaną treść na wyjściu standardowym.
Fragment wiersza poleceń > spis.htm
przekieruje sygnał z wyjścia standardowego
(terminala) do pliku spis.htm
. Reguły zamiany określimy następująco:
jeżeli kolejny wiersz
pliku kończy się frazą .htm
lub .html
,
to przekształć go do postaci <a href="wiersz">wiersz</a>
.
Inne wiersze kopiuj na wyjście bez zmian (nie będą miały odsyłaczy).
Dla uproszczenia założymy, że ścieżka dostępu do pliku może zawierać
wszystkie drukowalne znaki ASCII, to znaczy znaki
o numerach od 32 (x20, znak spacji
) do 126 (x7e, znak tyldy ~
).
(Zauważmy, że zestaw ten zawiera oba ukośniki /
i \
pełniące role łączników nazw w ścieżkach oraz dwukropek :
stanowiący część nazwy stacji dysków.)
Założymy też, że rozszerzenia nazw pisane są małymi literami.
Na końcu (tylko w DOS/Windows)
trzeba będzie zastąpić ukośniki \
ukośnikami /
.
W języku reguł programu sed
wyrazić to można następująco:
s/[ -~]*\.html$/<a href="&">&<\/a>/g s/[ -~]*\.htm$/<a href="&">&<\/a>/g s/\\/\//g
lub może nieco mniej czytelnie (chociaż dla starszych wersji sed
sposób ten jest bardziej odpowiedni)
s/[\x20-\x7e]*\.html$/<a href="&">&<\/a>/g s/[\x20-\x7e]*\.htm$/<a href="&">&<\/a>/g s/\\/\//g
Niestety, postać tych poleceń jest dość trudna do odczytania dla nieprzygotowanego użytkownika. O wiele łatwiej jest je konstruować, niż odczytywać.
Powstały plik trzeba uzupełnić o nagłówek i epilog języka HTML
.
Można to zrobić na przykład tak: najpierw umieścić w spisie pusty
nagłówek o treści np. takiej:
<html><head> <meta name="author" content="My we własnej osobie" /> <meta name="generator" content="Tak! sami umiemy generować takie dokumenty!" /> <title>Tytuł spisu</title> </head><body> <h1>Tytuł spisu</h1> <pre>
Zrobimy to, kopiując nagłówek z wcześniej przygotowanego pliku
o nazwie naglowek.html
.
Następnie dopiszemy do niego wydruk wygenerowany przez program sed
,
a całość zamkniemy epilogiem, przechowywanym w pliku nazwanym tu symbolicznie
epilog.html
. Jego treść stanowią polecenia zamykające:
</pre></body></html>
Czyli:
type nalgowek.html > spis.htm sed -f reguly spis.txt >> spis.htm type epilog.html >> spis.htm
I to już wszystko.
Jeżeli w naszym przykładzie wiersza pliku spis.txt
roz
ma wartość htm
,
to odpowiedni wiersz na wyjściu będzie zawierać napis
<a href="ścieżka/plik.htm">ścieżka/plik.htm</a>
Oto odpowiedni plik reguł. Proszę sprawdzić, jak działa.
Niepoprawne napisy typu str. 35-56 oraz str. 35 - 56 w dokumencie HTML zamieniaj na poprawne str. 35–56.
Oto plik reguł.
Zbuduj samodzielnie plik reguł.
Należy usunąć ciągi znaków rozpoczynające się znakiem <
,
a kończące się znakiem >
, lecz nie zawierające znaku
>
wewnątrz; zbuduj samodzielnie plik reguł.
Co ze znacznikami, które zaczynają się w jednym wierszu, a kończą w innym?
Co z symbolicznymi nazwami jednostek znakowych (jak
)?
Chcielibyśmy, żeby automat rozpoznał przynajmniej podstawowe elementy
blokowej struktury dokumentu znakowego i wstawiał odpowiednie znaczniki
HTML. Konieczne minimum to zastąpienie pustych wierszy znacznikami
zakończenia poprzedniego akapitu i rozpoczęcia następnego oraz wstawienie
„prologu” i „epilogu” dokumentu. Można też pomyśleć
o traktowaniu niektórych akapitów (np. tych rozpoczynających się gwiazdką
lub kreską poziomą) jako elementów listy. Ciągi znaków o ustalonym znaczeniu
(jak np. --
, ---
,
,,
, ''
,
...
, &
)
powinny zostać zastąpione nazwami odpowiadających im jednostek znakowych.
Przemyśl zagadnienie i zbuduj samodzielnie plik reguł realizujący wybraną
część tego projektu.
tr
: automatyczny translator znaków
W większości przykładów użycia edytora strumieniowego,
włączonych do bieżącego opracowania, zadanie sprowadza się do dokonania
ciągu zamian w przetwarzanym tekście. Nie jest to jedyny możliwy sposób
użycia sed
, lecz niewątpliwie jest najczęściej wykorzystywany
i w związku z tym najważniejszy. W bieżącym podrozdziale zostanie omówione
wyspecjalizowane narzędzie o nazwie tr
(ang. TRansliterate).
Jest ono przeznaczone do automatyzacji prostego, a jednocześnie istotnego etapu
prac redakcyjnych nad plikami danych znakowych, polegającego na ustalonej
zamianie pojedynczych znaków.
Zakres zastosowań tr
jest ograniczony do przypadków,
kiedy zamierzamy zastąpić znaki w całym pliku, bez względu na kontekst.
Program tr
czyta plik wejściowy i buduje
na jego podstawie plik wynikowy, w którym wszystkie wystąpienia
znaków z pewnego zbioru zostaną zastąpione odpowiadającymi im znakami
z innego zbioru. Zaawansowane opcje pozwalają ponadto usuwać wybrane
powtórzenia znaków oraz usuwać wszystkie wystąpienia wskazanych znaków.
Programowi trzeba zatem przekazać opis dwóch ciągów znaków.
Mimo że tr
nie działa na wyrażeniach regularnych,
tylko na pojedynczych znakach, to akceptuje w opisie ciągów
znaków zastępowanych i zastępujących te elementy składni wyrażeń
regularnych, które służą do definiowania zbiorów znaków.
Szczegółowe zasady używania programu tr
opisuje
jego instrukcja użytkowania.
Zadanie to było rozważane przy okazji omawiania pracy z edytorami interaktywnymi.
Znak nowego wiersza bywał opisywany dwojako: albo techniką kopiuj–wklej wzorzec,
albo przez odwołanie do nazwy \n
w notacji wyrażeń regularnych.
Chcąc użyć programu tr
do wykonania polecenia:
w trakcie czytania plikudane-wejsciowe
zmieniaj napotkane średniki na znaki końca wiersza, a wynik zapisz w plikuplik-wynikowy
powinniśmy sformułować następujące polecenie systemowe:
tr ";" "\n" dane-wejsciowe > plik-wynikowy
W tym przypadku użycie wyrażeń regularnych nie zawsze prowadzi do sukcesu.
W wielu programach wyszukiwanie wzorca odbywało się zawsze w obrębie wiersza,
zaś znak końca wiersza siłą rzeczy nie może znaleźć się we jego wnętrzu.
Program tr
czyta dane znak po znaku, zatem jest w stanie wyszukać
i przetworzyć także znaki końca wiersza:
tr "\n" ";" dane-wejsciowe > plik-wynikowy
Następujący sposób użycia tr
spowoduje zamianę wszystkich
małych liter łacińskich i polskich na odpowiadające im wielkie litery:
tr "a-ząćęłńóśźż" "A-ZĄĆĘŁŃÓŚŹŻ" dane-wejsciowe > plik-wynikowy
W przeciwieństwie do rozpatrywanych wcześniej ciągów wielu zamian
dokonywanych kolejno w obrębie całego pliku, tr
operuje
na bieżącym znaku, który natychmiast po przetworzeniu wysyła na wyjście.
Nic więc nie stoi na przeszkodzie, by wystąpienia pewnego ustalonego
znaku (powiedzmy +) zastąpić innym znakiem (powiedzmy -),
a jednocześnie nakazać także zamianę w odwrotnym kierunku.
Oto stosowne polecenie:
tr "\+\-" "\-\+" dane-wejsciowe > plik-wynikowy
(Odwrotne ukośniki są niezbędne, gdyż znaki + i - mają specjalne znaczenie w składni wyrażeń regularnych.)
sed
i tr
.
sort
: sortowanie danych w pliku
Program sort
nie jest filtrem, ponieważ dane da się ostatecznie uporządkować
dopiero po odczytaniu wszystkich wierszy z wejścia.
Mimo to operuje on na standardowym pliku wejściowym i standardowym pliku wynikowym,
a sposób jego użycia jest analogiczny do sposobu używania filtrów.
Dostępna instrukcja użytkowania programu sort
dotyczy wersji polecenia z systemu GNU.
Systemowe polecenie sort
z systemu Windows
ma nieco inne opcje.
Plik wejściowy | Wynik poleceniasort plik1 > plikwynikowy (sortowanie alfabetyczne według pierwszego pola — uwaga na długość ciągów znaków) |
Wynik poleceniasort -k1.1,1.2 plik1 > plikwynikowy (sortowanie alfabetyczne według dwóch pierwszych znaków pierwszego pola) |
Wynik poleceniasort -n plik1 > plikwynikowy (sortowanie numeryczne według pierwszego pola) |
Wynik poleceniasort -k2 plik1 > plikwynikowy (sortowanie alfabetyczne według drugiego pola) |
|||||
---|---|---|---|---|---|---|---|---|---|
|
|
|
|
|
Przeformatuj plik geometra.txt
tak,
by opis każdego pojęcia zawierał się w pojedynczym wierszu, tak jak tutaj:
Punkt jest czymś, co nie ma żadnej wielkości (Euklides). Punkt ma określone jedynie położenie. Prosta posiada tylko jeden wymiar: długość (Euklides). Przez dwa różne punkty przechodzi dokładnie jedna prosta. Odcinek jest fragmentem prostej, zawartym między dwoma punktami. Łamana to linia utworzona z kolejnych odcinków (krawędzi, boków) tak, że koniec każdego odcinka jest jednocześnie początkiem następnego. Bok łamanej to odcinek, będący częścią łamanej. Łamana zamknięta to taka łamana, w której koniec ostatniego odcinka jest jednocześnie początkiem pierwszego. Wielokąt to obszar na płaszczyźnie, ograniczony łamaną zamkniętą. Bok wielokąta to bok łamanej, która go ogranicza.
Uporządkuj opisy alfabetycznie, wynik umieść w pliku slowniczek-geom.txt
:
sort < geometra.txt > slowniczek-geom.txt
uniq
W wyniku kompletowania danych (np. drogą ankietowania, zbierania zamówień,
łączenia list uczestników) powstają ciągi danych, w których ten sam element
może występować wielokrotnie. W zapisie znakowym jednemu elementowi ciągu
odpowiada jeden wiersz pliku znakowego. Posortowanie takiego pliku spowoduje
zgrupowanie wszystkich elementów o tej samej wartości w bloku kolejnych wierszy.
Program uniq
(z ang. unique = jednoznaczny)
odczytuje dane z wejścia standardowego, a na wyjściu standardowym zapisuje tylko pierwszy
z każdego bloku identycznych wierszy. Jeżeli więc ciąg danych wejściowych
jest uporządkowany, to plik wynikowy zawiera po jednym wierszu z opisem
każdego elementu.
Dostępna jest instrukcja użytkowania programu uniq
w polskim tłumaczeniu.
Plik wejściowy | Wynik polecenia uniq plik1 > plikwynikowy | ||
---|---|---|---|
|
|
Grupa obserwatorów została skierowana do odczytania danych pomiarowych
ze stacji terenowych. Obserwatorzy podzielili obszar na rejony, w których
osobiście odczytywali pomiary. Jednak niektóre stacje położone w pobliżu granicy
rejonów zostały sprawdzone także przez obserwatorów z sąsiedniego rejonu.
Każdy z obserwatorów zapisał dane w pliku znakowym
o nazwie postaci obserwacje.i
i treści:
numer-stacji data wartość-odczytu
w którym separatorami danych są pojedyncze znaki tabulacji. Przed opracowaniem danych połączono wszystkie odczyty w jeden plik:
cat obserwacje.1 >> obserwacje cat obserwacje.2 >> obserwacje … cat obserwacje.n >> obserwacje
(polecenie cat
należy do systemu UNIX;
w systemach DOS i Windows można skorzystać z polecenia type
),
następnie uporządkowano:
sort < obserwacje > obserwacje.up
i usunięto powtarzające się elementy:
uniq < obserwacje.up > obserwacje
W wyniku tych operacji otrzymano plik obserwacje
,
zawierający po jednym egzemplarzu każdego odczytu.
W jednym z etapów pracy powstał plik pomocniczy obserwacje.up
,
który nie jest już potrzebny i można go usunąć.
Wykorzystanie mechanizmu potoku pozwala całą pracę zapisać w postaci jednego
polecenia uruchamiającego trzy programy (cat
, sort
i uniq
) odpowiedzialne za kolejne etapy przetwarzania:
cat obserwacje.* | sort | uniq > obserwacje
Technika ta ma dodatkową zaletę: danych pośrednich nie trzeba zapisywać w plikach tymczasowych.
comm
Operacja łączenia tworzy plik będący sumą zawartości dwóch lub większej liczby danych plików.
Uzupełnieniem wyznaczania sumy jest wyznaczanie różnic zawartości i części wspólnej zawartości dwóch plików.
Jednym z narzędzi, które to umożliwiają, jest program o nazwie
comm
(z ang. common = wspólny).
Czyta on wiersz po wierszu dwa pliki i wypisuje na wyjściu standardowym trzy kolumny:
pierwsza zawiera tylko wiersze, których nie ma w drugim pliku;
druga zawiera tylko wiersze, których nie ma w pierwszym pliku;
trzecia zawiera wiersze obecne w obu plikach.
Tworzenie każdej z tych kolumn można wyłączyć za pomocą odpowiedniej opcji.
Podczas przetwarzania comm
zakłada, że pliki wejściowe zostały posortowane wierszami;
jeżeli tak nie jest, to wyniki są nieprzewidywalne.
Dostępna jest instrukcja użytkowania programu comm
w polskim tłumaczeniu.
Pliki wejściowe | Wynik polecenia comm plik1 plik2 > plikwynikowy | ||||
---|---|---|---|---|---|
|
|
|
xargs
Pojedynczy zestaw argumentów można przekazać programowi w wierszu poleceń.
Program xargs
(ang. eXecute with ARGumentS = wykonaj z argumentami)
wykonuje wskazane polecenie wielokrotnie, za każdym razem przekazując mu kolejną
porcję danych z wejścia standardowego jako listę argumentów.
start odczytaj wiersz poleceń; dopóki (nie doszedłeś do końca pliku standardowego wejścia) wykonuj ( pobierz kolejną porcję danych z wejścia standardowego; wykonaj polecenie określone przez opcje wiersza poleceń z dołączonymi odczytanymi argumentami; ); koniec pracy.
Dobrze, ale cóż to jest „kolejna porcja danych”?
Program xargs
jest na tyle elastyczny,
że pozwala użytkownikowi samemu sprecyzować to pojęcie.
Może to być na przykład: jeden argument, dwa argumenty,
wszystkie argumenty z jednego wiersza pliku wejściowego itp.
Dane na wejście standardowe mogą być podawane przez operatora
bezpośrednio z konsoli: (xargs polecenie
),
odczytywane z pliku znakowego (przekierowanie wejścia standardowego:
xargs polecenie < plik-argumentów
)
lub generowane przez jakiś program (praca potokowa:
program | xargs polecenie
).
spis
,
zawierający spis treści tej kartoteki
Pokażemy, jak poradzić sobie z tym zadaniem w środowisku systemu Windows.
Polecenie dir > spis
umieszcza w kartotece bieżącej plik spis
zawierający wydruk polecenia dir *.*
, czyli spis zawartości kartoteki.
dir /b/s/ad \*.*
.
piszkart.cmd
o następującej zawartości:
dir %1 > %1\spis
xargs --max-lines=1 piszkart.cmd
spowoduje wykonanie kolejnych poleceń postaci
Jeżeli na wejściu umieścimy listę kartotek:piszkart.cmd kolejny wiersz wejścia
to poleceniedir /s/b/ad \*.* | xargs --max-lines=1 piszkart
piszkart.cmd
założy plik ze spisem w każdej kartotece,
której nazwa wystąpi w listingu.
del piszkart.cmd
usuwamy niepotrzebny już
plik skryptowy (chyba że chcielibyśmy go zachować na lepsze czasy).
W opisie dla uproszczenia pominięto fakt, że nazwy kartotek w systemie Windows mogą zawierać spacje.