To jest stara wersja strony!
SED i AWK
Do przygotowania
Przypomnieć sobie pracę z jednym z wybranych edytorów (np. vi, emacs, itp).
Powtórzyć zasady pisania filtrów i skryptów powłoki sh.
Przypomnieć sobie funkcję manipulujące łańcuchami znaków w języku C.
Przeczytać następujące artykuły:
Wersja angielska:
Wprowadzenie
sed i awk są narzędziami strumieniowego przetwarzania tekstu.
Ich główną zaletą jest możliwość czytania ze standardowego wejścia i wyświetlanie rezultatów na standardowym wyjściu (dlaczego jest to zaleta?).
Dane mogą być wczytywane również z pliku.
Podczas pracy nie modyfikują żadnych plików.
Posiadają szereg instrukcji manipulujących łańcuchami znaków (wstawianie, zastępowanie, itp).
Instrukcje mogą być podawane z linii komend (w przypadku małych ilości poleceń) lub czytane z pliku (co zwiększa czytelność w przypadku dużej ilości poleceń).
Obsługują wyrażenia regularne!!!
Wyrażenia regularne
ang. regular expressions, w skrócie regex lub regexp
Są wzorcami opisującymi łańcuchy znaków.
Umożliwiają odnalezienie określonej regularności w danej sekwencji znaków.
Definiowanie wyrażeń regularnych
Wyrażenia regularne składają się dwóch podstawowych zestawów znaków:
Kolejność znaków w wyrażeniu jest istotna.
Wielkość liter w wyrażeniu jest także istotna.
Wyrażenie g opisuje wszystkie łańcuchy znaków zawierające literę g np. gitara (ale nie Gitara), zagadka, log.
Wyrażenie ba opisuje wszystkie łańcuchy znaków zawierające podciąg ba np. baca, zabawa, żaba.
Kropka . określa dowolny znak oprócz znaku końca wiersza np. a.c pasuje do: aac, abc, ale nie pasuje do ac.
Nawias kwadratowy pozwala na określenie listy, zakresu znaków np. a[abc]c pasuje do napisów zawierających podciągi: aac, abc, acc - czyli pomiędzy znakami a i c może wystąpić tylko i wyłącznie jeden znak z podanych w nawiasie. Uwaga, należy zauważyć że powyższe wyrażenie pasuje również do: aabc, acccc, itp. Powyższe wyrażenie jest równoznaczne z a[a-c]c poprzez zdefiniowane zakresu za pomocą - myślnika. Istnieje także możliwość listowania zakresów: [a-z0-9] - oznacza dowolną małą literę od a do z lub dowolną cyfrę.
Negacja zakresu ^. Znak ^ umieszczony jako pierwszy wewnątrz nawiasu kwadratowego oznacza jego negację np. [^a-c] oznacza wszystkie znaki oprócz a, b, c.
Znak ^ ma także drugie znaczenie (żeby nie było tak prosto
). Oznacza początek łańcucha znaków, czyli
^ab określa wszystkie łańcuchy znaków rozpoczynające się od
ab np.
abakus, natomiast nie pasuje do np:
żaba.
Podobne znaczenie do ^ ma znak $ oznaczający koniec łańcucha znaków.
Okrągłe nawiasy () służą do grupowania części wyrażeń (wykorzystywane do np. określania liczby powtórzeń danego wzorca).
Powtórzenia: liczba powtórzeń określa ilość wystąpienia danego wzorca w badanym łańcuchu znaków. Liczbę powtórzeń możemy zdefiniować w następujący sposób:
Gwiazdka * - zero lub więcej wystąpień poprzedzającego ją znaku np: a* pasuje do ab, aab, bab, baaab, ale też do: b.
Plus + - co najmniej jedno wystąpienie poprzedzającego znaku np: a+ pasuje do ab, aab, bab, baaab, ale nie do: b.
Znak zapytania ? po symbolu oznacza najwyżej jedno (być może zero) wystąpienie poprzedzającego wyrażenia.
Nawias klamrowy {} pozwala na dokładne określenie minimalnej i maksymalnej liczby powtórzeń:
{2,5} - minimalnie 2 a maksymalnie 5,
{3} - dokładnie 3 razy,
{5,} - co najmniej 5 razy,
{,6} - co najwyżej 6 razy.
Pionowa kreska (ang. pipeline) | to operator OR np. jeśli napiszemy a|b|c oznacza to, że w danym wyrażeniu może wystąpić a lub b lub c.
Jeżeli chcemy użyć jednego ze znaków kontrolnych jako zwykłego to poprzedzamy go backslash-em
\ np:
^\$ definiuje wszystkie łańcuchy znaków rozpoczynające się od znaku dolara
* ^[0-9]{2}-[0-9]{3}
* ^[1-4]{,1}[0-9]{1}
===== SED =====
* ang. S
tream ED
itor - edytor strumieniowy.
* Pomimo swej prostoty umożliwia wykonanie złożonych operacji na łańcuchach znaków.
* Program przyjmuje polecenia do wykonania z pliku lub z wiersza poleceń (jak zdefinować instrukcje do wykonania z linii poleceń a jak z pliku? - manual).
* Program wczytuje dane wejściowe linia po linii i dla każdej linii wykonuje wszystkie
instrukcje do wykonania!!!
===== AWK =====
* Nazwa pochodzi od pierwszych liter nazwisk jego autorów: Alfreda V. Aho, Petera Weinbergera i Briana Kernighana
* Jest to program interpretujący język skryptowy, służący do przetwarzania wyrażeń regularnych.
* Składnia języka jest bardzo podobna do składni języka C.
* Program wczytuje dane wejściowe rekord po rekordzie i dla każdego rekordu wykonuje wszystkie polecenia.
===== Ćwiczenia =====
==== SED ====
- Przeczytać manual do programu. Zwrócić uwagę na polecenia, ich składnię oraz sposób adresacji poleceń.
- Wyświetlić plik /etc/passwd
przy pomocy sed.
- Zamienić separator - dwukropek - w pliku /etc/passwd
na spację.
- Wyświetlić tylko
nazwy użytkowników zapisanych w pliku /etc/passwd
- Wyświetlić 4, 7, 10 i 13 linię pliku /etc/passwd
- Wyświetlić określone przedziałem (np. od 3. do 5. włącznie) linie pliku /etc/passwd
.
- Wyświetlić linie pliku /etc/passwd
opisujące osoby mające login zaczynający się na 'z'.
- Wyświetlić linie pliku /etc/passwd
opisujące osoby mające login zaczynający się na 'q' lub 'z'.
- Jak przy pomocy sed zaimitować polecenie grep -v
? np. dla frazy 'lo' (grep -v lo /etc/networks
)
- Jak zamienić w pliku wszystkie słowa root
na twój login (przetestuj na pliku /etc/aliases
)?
- Jak zamienić słowo 'root' na twój login w pliku, ale tylko w wierszach, w których występuje 'www'? A jak tam gdzie nie występuje?
- Jak usunąć z pliku puste linie?
- Jak zamienić przy pomocy sed wszystkie litery 'r' na 'k'?
- W jaki sposób zakodować szyfrem ROT13 plik przy pomocy sed (szyfr zamienia litery na występujące 13 liter dalej, np. a↔n, b↔o, itd.)?
- Przy pomocy polecenia sed zakomentuj linijkę default w pliku /etc/networks
.
- W jaki sposób przy użyciu sed wstawić kolumnę X po pierwszym znaku wiersza (dodatkowy znak X w każdym wierszu)? A jak po piątym?
- Jak przy pomocy sed powtórzyć 3 razy pierwsze dwie litery każdego wiersza w pliku?
- Wylistuj wszystkie wiersze pliku /etc/mime.types
zaczynające się od video
i wyświetl ich numer.
- Napisz polecenie sed imitujące polecenie cut -d: -f2
.
- W jaki sposób zmienić kolejność słów (np. w pliku /etc/aliases
)?
Jest: news: root
Zrób: root: news
- Napisz polecenie sed imitujące cat -n
.
- Napisać skrypt
programu sed który ustawi powłokę startową wszystkim użytkownikom grupy is1 (folder domowy w katalogu is1) na /bin/tcsh
. Skrypt ma wydrukować całą zawartość zmienionego pliku na ekranie wraz z zaznaczeniem zmienionych linii - tak jak jest to przedstawione poniżej.<code>
—————————-
linia w której nastąpiła zmiana powłoki
—————————-
</code>
- Napisać skrypt
programu sed wyświetlający linię zawarte w pliku /etc/passwd
w odwrotnej kolejności.
==== AWK ====
=== Ćwiczenia ===
- Przeczytać manual do programu zwrócić uwagę na:
* wbudowane zmienne,
* wbudowane funkcje,
* wbudowane instrukcje sterujące.
- Jak awk interpretuje spacje?
- Co określają następujące zmienne: FS
, RS
, NF
, NR
, OFS
, ORS
?
- Kiedy wykonywane są instrukcje zawarte w blokach BEGIN
oraz END
w przypadku kiedy zródło danych składa się z wielu plików?
- Zapisać dowolną stronę internetową (może być także ta) w formacie HTML. Wyświetlić jej zawartość przy pomocy polecenia cat a następnie przy pomocy programu awk usunąć wszystkie znaczniki HTML z treści. Rezultat należy wyświetlić na ekranie.
- Do powyższego zadania dopisać element filtru, który usunie wszystkie puste linie, oraz te które posiadają tylko białe znaki.
=== Zadania ===
Zadanie1
Przeanalizować poniższy skrypt (plik userlist
):
<code>
#!/bin/sh
who | awk '{print $1}' | sort | uniq | xargs -i„{}” grep -e „^{}:” /etc/passwd | awk -f awkuserlist
</code>
oraz plik awkuserlist
(skrypt programu awk) który jest w nim wykorzystany:
<code>
BEGIN {
FS=„:”
print „<xml version=„1.0”>”;
}
{
match($5, „^[^, ]*”);
imie=substr($5, RSTART, RLENGTH);
match($5, „ [^, ]*”);
nazwisko=substr($5, RSTART+1, RLENGTH-1);
login=$1;
uid=$3;
gid=$4;
home=$6;
shell=$7;
print „<osoba>”;
print „<imie>„imie”</imie>”;
print „<nazwisko>„nazwisko”</nazwisko>”;
print „<login>„login”</login>”;
print „<uid>„uid”</uid>”;
print „<gid>„gid”</gid>”;
print „<home>„home”</home>”;
print „<shell>„shell”</shell>”;
print „</osoba>”;
}
END {
print „</xml>”;
}
</code>
* Jaki jest rezultat wykonania skryptu userlist
* Dopisać skrypt programu awk który przeanalizuje strumień wyjściowy skryptu userlist
i przekształci go w następujący sposób:
* Format wejściowy:
<code xml>
<osoba>
<dana1>wartosc1</dana1>
<dana2>wartosc2</dana2>
<dana3>wartosc3</dana3>
<dana4>wartosc4</dana4>
</osoba>
</code>
* Format wyjściowy:
<code>
——————————————-
dana1: wartosc1
dana2: wartosc2
dana3: wartosc3
dana4: wartosc4
——————————————-
</code>
* Przykład:
* Dla wejścia:
<code xml>
<osoba>
<imie>Jan</imie>
<nazwisko>Kowalski</nazwisko>
<login>jkowalski</login>
<uid>1</uid>
<gid>1</gid>
<home>/home/users/jkowalski</home>
<shell>/bin/bash</shell>
<miasto>Kraków</miasto>
</osoba>
</code>
* Skrypt powinien wygenerować wyjście:
<code>
——————————————-
imie: Jan
nazwisko: Kowalski
login: jkowalski
uid: 1
gid: 1
home: /home/users/jkowalski
shell: /bin/bash
miasto: Kraków
——————————————-
</code>
Zadanie 2
BibTeX
to narzędzie służące do formatowania bibliografii.
Operuje ono na danych zawartych w plikach o rozszerzeniu „bib”
zawierających dane bibliograficzne.
Przykład pliku: publikacje.bib.txt.
Poszczególne wpisy bibliograficzne mają następującą postać:
<code>
@rodzaj{klucz,
author = {wartość},
title = {wartość},
year = wartość,
other = {wartość}
}
</code>
Zadanie polega na stworzeniu skryptu bash
,
który przy użyciu awk
wybierze z pliku tylko te wpisy bibliograficzne,
które odpowiadają zapytaniu użytkownika.
Tzn. skrypt zapisany w pliku szukaj
powinien obsługiwać
następujące opcje (-a, -t, -k):
* ./szukaj -a Nalepa
- wyszuka wszystkie publikacje autorstwa Nalepy (te wpisy bibtexowe, w których polu author
występuje Nalepa
),
* ./szukaj -t slowo
- wyszuka wszystkie publikacje zawierające w tytule ciąg slowo
,
* ./szukaj -k slowo
- wyszuka wszystkie publikacje zawierające ciąg slowo
w dowolnym polu.
Zadanie 3**
Napisz skrypt programu awk który policzy i wyświetli średnią ocen dla każdego studenta.
Lista studentów oraz ocen jest zapisana w pliku, którego nazwę podajemy jako parametr uruchomienia programu awk (nazwa pliku nie może być zakodowana wewnątrz skryptu).
Format pliku zawierającego listę studentów oraz ocen jest następujący:
login_1:ocena_1,ocena_2,ocena_3
login_2:ocena_1,ocena_2,ocena_3,ocena_4
Należy przyjąć następujące założenia:
login_n
- jest loginem danego studenta.
login_n
- istnieje w pliku /etc/passwd
.
Liczba studentów nie jest określona, definiuje ją tylko i wyłącznie liczba linii w pliku.
Plik zawiera tylko linie w powyższym formacie - przyjmujemy jako aksjomat i nie weryfikujemy tej kwestii.
ocena_n
- oznacza ocenę, liczbę ze zbioru {2.0, 3.0, 3.5, 4.0, 4.5, 5.0}
(nie ma przymusu sprawdzania poprawności - przyjmujemy że oceny są wpisane poprawnie).
Liczba ocen dla każdego studenta nie jest określona i może być różna.
Spacje w pliku nie wpływają na sposób jego przetwarzania.
Jako rezultat, skrypt powinien wyświetlić informację o uzyskanej średniej ocenie przez każdego studenta w następującym formacie:
Srednia ocena dla Imie Nazwisko wynosi: X
gdzie:
Imie Nazwisko
- oznaczają odpowiednio imię i nazwisko studenta pobrane z pliku /etc/passwd
(uwaga: nie login jak to jest w pliku wejściowym).
X
- wartość średniej oceny z dokładnością do dwóch miejsc po przecinku.
Napisany skrypt nie może używać żadnych poleceń zewnętrznych.
Przykłady plików: wejściowego oraz wyjściowego.
Dla zainteresowanych