Home Dokumentacje Sed w przykładach, część pierwsza
18 | 08 | 2019
Sed w przykładach, część pierwsza
Wpisany przez Daniel Robbins   

Uwaga: Oryginalna wersja tego artykułu została opublikowana w IBM developerWorks i jest własnością Westtech Information Services. Poniższy dokument jest poprawioną przez zespół GDP wersją oryginalnego tekstu i nie jest już aktualizowany.

Sed w przykładach, część pierwsza

Daniel Robbins Autor
Tomasz Bukowski Tłumaczenie

Zaktualizowano 9 października 2005
Oryginalna wersja tego dokumentu została po raz ostatni zaktualizowana 14 maja 2010. Jeśli chcesz pomóc w aktualizacji tego dokumentu do najnowszej wersji, skontaktuj się z Adres poczty elektronicznej jest chroniony przed robotami spamującymi. W przeglądarce musi być włączona obsługa JavaScript, żeby go zobaczyć. , koordynatorem polskiego projektu tłumaczeń dokumentacji Gentoo.

1. Poznać porządny UNIX-owy edytor

Wybierz edytor...

W świecie UNIX-ów mamy spory wybór jeżeli chodzi o edycję plików. Jest vi, emacs, jed i masa innych. Każdy ma swój ulubiony edytor. Z jego pomocą z łatwością poradzi sobie z zadaniami jakie czekają podczas programowania, czy administracji UNIX-em.

Edytory interaktywne są świetne, ale mają pewne ograniczenia. Ich główna cecha - oddziaływanie przez użytkownika podczas edycji - może okazać się ich słabością. Szczególnie w sytuacji, gdy potrzebujemy wprowadzić małe zmiany w pewnej grupie plików. Wypada wtedy za każdym razem odpalać nasz edytorek, wprowadzić żądane zmiany - wszystko ręcznie. Ale istnieje lepsze rozwiązanie ...

Przedstawienie Seda

Było by miło, gdyby można było zautomatyzować proces edycji istniejących plików przez polecenie w konsoli lub napisanie prostego skryptu. Na szczęście w takich sytuacjach istnieje lepsza droga niż ręczna edycja - sed.

sed jest małym edytorem strumieniowym, który można znaleźć we wszelkiej maści UNIX-ach (czyli także w Linuksie). Sed ma wiele przydatnych funkcji. Po pierwsze zajmuje naprawdę niewiele. Po drugie jest to edytor strumieniowy, dzięki czemu można przeprowadzać edycję na danych otrzymanych z stdin (takich jak pipe). Nie jest konieczne, aby te dane były zapisywane na dysku. Ponieważ dane można łatwo "wpuścić" przez strumień wejścia do seda, łatwe staje się używanie seda pod konsolą lub skryptach. Spróbuj zrobić to samo ze swoim ulubionym edytorem...

GNU sed

Dobrą wiadomością dla użytkowników Linuksa jest to, że jedna z lepszych wersji seda wydana jest jako GNU sed. Każda dystrybucja Linuksa zawiera seda (lub chociaż powinna). Na popularność GNU seda wpływa nie tylko jego otwarty charakter, ale również fakt, że zawiera wiele rozszerzeń które oszczędzają sporo czasu. GNU sed jest także pozbawiony wielu ograniczeń, które miała wcześniejsza i główna wersja (np. limit długości wiersza - GNU sed poradzi sobie z linią każdej długości. ;)

Najnowszy GNU sed

Podczas pisania tego artykułu zauważyłem, że niektóre serwisy internetowe odwołują się do wersji 3.02a GNU seda. Co dziwne - nie mogłem znaleźć jej na ftp://ftp.gnu.org (patrz materiały). Szukając w innych źródłach, znalazłem tę wersję na ftp://alpha.gnu.org w /pub/sed. Szczęśliwy ściągnąłem, skompilowałem i zainstalowałem tą wersję. Jak okazało się tylko po to, aby za parę minut okazało się, że najnowszą wersją seda jest 3.02.80. Można ją znaleźć tuż obok 3.02a na ftp://alpha.gnu.org. W końcu po zainstalowaniu wersji 3.02.80 byłem gotowy do pracy.

Praca z sedem na całego

W tej serii artykułów będziemy używać GNU sed 3.02.80. Niektóre z przykładów mogą nie działać poprawnie na starszych wersjach GNU sed. W przypadku używania nie-GNU seda można napotkać spore utrudnienia. Wystarczy poświęcić trochę czasu na zainstalowanie najnowszej wersji GNU seda. ;) Można zyskać nie tylko pewność, że zadziałają wszystkie przykłady, ale i dostać do użytku najlepszą wersję wspaniałego edytora tekstu.

Przykłady użycia seda

Sed działa poprzez poddawanie edycji danych wejściowych w sposób jaki zażąda tego użytkownik. Komendy i akcje w sedzie podejmowane są dla każdego wiersza po kolei. Wyrzuca on rezultat pracy na standardowe wyjście (stdout), nie modyfikując oryginalnych plików wejściowych.

Rzućmy okiem na parę przykładów. W pierwszym przykładzie pokażę po prostu jak działa sed. Na początku ważne jest zrozumienie sposobu działania seda, później przyjdzie czas na jego efektywne wykorzystanie. Oto pierwszy przykład:

Listing 1.1: Przykład użycia seda

$ sed -e 'd' /etc/services

Jeżeli wykonamy to polecenie, nie otrzymamy nic na wyjściu. Dlaczego? W tym przykładzie wywołaliśmy seda z jednym z poleceń edycyjnych - d Sed otworzy plik /etc/services, wczyta wiersz do bufora, wykona wskazane operacje (u nas "d" - usuń wiersz) i wypisze zawartość bufora (w naszym przykładzie bufor będzie pusty!). Takie czynności będą powtarzane dla każdego kolejnego wiersza. Nie otrzymamy nic na wyjściu, ponieważ za pomocą polecenia d usunęliśmy każdy wiersz!

Jest jeszcze parę spraw do omówienia w tym przykładzie. Po pierwsze - plik /etc/services nie został tak naprawdę zmodyfikowany. Stało się tak, ponieważ sed tylko czyta z pliku - używa go jako wejścia danych nie próbując go modyfikować. Drugą sprawą jest fakt, że sed jest zorientowany wierszowo. Polecenie d nie oznaczało po prostu usunięcie wszystkiego naraz - sed wczytywał linijkę po linijce do bufora (zwanego buforem wzorca), a następnie wykonywał polecenie d i wypisywał zawartość bufora (u nas nic). Później dowiemy się w jaki sposób używać adresowania zakresów aby móc kontrolować dla których wierszy zostanie wykonane polecenie d.

Trzecią rzeczą o której należy wspomnieć, jest zamknięcie polecenia d w pojedynczych apostrofach. Takie zamykanie poleceń w sedzie jest dobrym zwyczajem i nie powoduje kolizji z poleceniami konsolowymi.

Inny przykład zastosowania seda

Oto przykład użycia seda do usunięcia pierwszej linii z pliku /etc/services:

Listing 1.2: Inny przykład zastosowania seda

$ sed -e '1d' /etc/services | more

Jak łatwo zauważyć, polecenie to jest bardzo podobne do użytego wcześniej d z wyjątkiem tego, że zawiera ono teraz 1. Tym razem użyliśmy polecenia d poprzedzonego adresem. Poprzez użycie adresowania możemy przeprowadzić edycję tylko wybranych linii.

Adresowanie

Spróbujmy teraz przyjrzeć się w jaki sposób zaadresować pewien zakres. W tym przykładzie użyjemy seda do usunięcia linijek od 1 do 10 :

Listing 1.3: Adresowane zakresu

$ sed -e '1,10d' /etc/services | more

Kiedy oddzielamy dwa adresy przecinkiem sed traktuje to jako zakres na którym przeprowadzi żądane operacje. Zakres rozpoczyna się od pierwszego adresu, kończy na drugim. W przykładzie polecenie d zostało zastosowane dla wierszy od 1 do 10 włącznie. Inne wiersze zostały pominięte.

Adresowanie z pomocą wyrażeń regularnych

Nadszedł czas na bardziej zaawansowany przykład. Powiedzmy, że chcemy obejrzeć plik /etc/services, ale nie jesteśmy zainteresowani oglądaniem komentarzy. Jak wiadomo komentarze w pliku /etc/services, to linie zaczynające się od znaku '#'. Aby pominąć komentarze wystarczy usunąć każdą linijkę zaczynającą się od znaku '#'. Można to zrobić tak :

Listing 1.4: Usuwanie linii zaczynających się od #

$ sed -e '/^#/d' /etc/services | more

Odpalmy ten przykład i zobaczmy co otrzymamy. Zauważymy, że sed wykonał swoje zadanie poprawnie.

Aby zrozumieć składnię '/^#/d' podzielmy to polecenie na kawałki. Najpierw usuńmy 'd' -- tak jak było to powiedziane wcześniej, jest to kasowanie wiersza. Zostaje nam '/^#/' - jest to nowy rodzaj adresowania z użyciem wyrażeń regularnych. Takie wyrażenie jest zawsze zamknięte między '/'. Definiuje ono wzorzec, a do wszystkich pasujących linii zostanie zastosowane polecenie znajdujące się za nim (u nas 'd' - usunięcie)

Więc '/^#/' jest wyrażeniem regularnym. Ale co to robi? To chyba jest odpowiedni moment, aby opowiedzieć szerzej o wyrażeniach regularnych.

Odświezenie wiadomości o wyrażeniach regularnych

Można użyć wyrażeń regularnych, aby określić wzorzec, który chcemy znaleźć w tekście. Jeżeli ktoś używał znaku '*' w konsoli - używał czegoś co jest podobne do wyrażeń regularnych. Poniżej znajduje się lista specjalnych znaków, które mogą zostać użyte w wyrażeniach.

Znaki Opis
^ Oznacza początek wiersza
$ Oznacza koniec wiersza
. Oznacza pojedynczy znak
* Oznacza zero lub więcej wystąpień poprzedniego znaku
[ ] Wszystkie znaki pomiędzy [ i ]

Chyba najlepszym sposobem na sprawne wejście w świat wyrażeń regularnych jest zobaczenie kilku przykładów w akcji. Wszystkie będą zaakceptowane przez seda jako poprawny sposób adresowania. Oto kilka przykładów:

Wyrażenie regularne Opis
/./ Oznacza wiersz, który zawiera co najmniej jeden znak
/../ Oznacza wiersz zawierający przynajmniej dwa znaki
/^#/ Oznacza wiersz zaczynający sie od '#'
/^$/ Oznacza wiersz pusty
/}^/ Oznacza wiersz, który kończy się '}' (bez spacji)
/} *^/ Oznacza wiersz kończący się '}' po której występuje zero lub więcej spacji
/[abc]/ Oznacza wiersz zawierający 'a', 'b' lub 'c'
/^[abc]/ Oznacza wiersz, który zaczyna się od 'a', 'b' lub 'c'

Zachęcam do wypróbowania kilku przykładów na własnej skórze. Potrzeba trochę czasu na oswojenie się z wyrażeniami regularnymi. A oto sposób ich poprawnego użycia:

Listing 1.5: Poprawne użycie wyrażenia regularnego

$ sed -e '/regexp/d' /sciezka/do/mojego/testowego/pliku | more

To spowoduje, że sed usunie każdy wiersz pasujący do wzorca. Jednak łatwiej było by wypisać pasujące wiersze, a te nie pasujące usunąć. Można tego dokonać poleceniem:

Listing 1.6: Wypisywanie pasujących wierszy

$ sed -n -e '/regexp/p' /sciezka/do/mojego/pliku | more

Zwróćmy uwagę na nową opcję, '-n', która nakazuje sedowi nie wypisywać wzorca, dopóki nie zostanie wydane odpowiednie polecenie. Łatwo także zauważyć, że zastąpiliśmy d poleceniem p, które to nakazuje sedowi wypisanie wiersza pasującego do wzorca.

Więcej o adresowaniu

Na razie powiedzieliśmy parę słów o adresowaniu wierszy, adresowaniu zakresów i wykorzystaniu wyrażeń regularnych do adresowania, ale możliwości jest więcej. Można zdefiniować dwa wyrażenia regularne oddzielone przecinkiem, a sed edytuje wszystkie wiersze znajdujące się między pierwszym a drugim wyrażeniem włącznie. Na przykład następujące polecenie wyświetli blok tekstu zaczynający się od wiersza zawierającego "POCZATEK", a skończywszy na wierszu zawierającym "KONIEC":

Listing 1.7: Wyświetlenie opisanego bloku tekstu

$ sed -n -e '/POCZATEK/,/KONIEC/p' /moj/plik | more

Jeżeli "POCZATEK" nie zostanie odnaleziony nic nie zostanie wyświetlone. Natomiast jeżeli sed odnajdzie "POCZATEK", ale nie odnajdzie "KONIEC", otrzymamy wszystkie wiersze od miejsca odnalezienia do końca. Dzieje się tak, ponieważ sed jest zorientowany strumieniowo - więc nigdy nie wie kiedy nastąpi "KONIEC".

Przykład ze źródłami C

Jeżeli ktoś chciałby zobaczyć jedynie zawartość funkcji main() w pliku źródłowym C, może napisać:

Listing 1.8: Podgląd funkcji main() z pliku źródłowego C

$ sed -n -e '/main[[:space:]]*(/,/^}/p' zlodlo.c | more

Polecenie zawiera dwa wyrażenia regularne '/main[[:space:]]*(/' i '/^}/' oraz polecenie p. Pierwsze wyrażenie regularne oznacza, że sed będzie szukał ciągu znaków "main" po którym może wystąpić dowolna ilość spacji i tabulatorów oraz otwarty nawias "(". To powinno nam pozwolić na znalezienie deklaracji funkcji main() zgodnie z ANSI C.

W tym wyrażeniu regularnym wystąpiła klasa znaków '[[:space:]]'. Jest to po prostu specjalne słowo-klucz które mówi sedowi aby brał pod uwagę TAB lub spacje. Zamiast pisać '[[:space:]]' można napisać '[', CTRL+V, tabulator i ']', ale chyba bardziej czytelna jest klasa znaków '[[:space:]]'.

Przejdźmy teraz do drugiego wyrażenia :'/^}/'. Sed będzie szukał znaku '}' na początku wiersza. Jeżeli plik źródłowy jest poprawnie sformatowany, sed powinien znaleźć zamykający nawias '}' funkcji main(). Jeżeli nie znajdzie - będzie wypisywał wszystko aż do końca pliku - taki jego urok.

Polecenie p robi to co zawsze - nakazuje sedowi wypisać linijkę (od kiedy mamy tryb "cichy" -n). Polecam wypróbowanie tego przykładu na kilku plikach C - powinniśmy dostać zawartość funkcji main() z "main()" i "}" włącznie.

W następnym odcinku

Na razie przedstawiłem tylko podstawy seda. Temat ten rozwinę w dwóch następnych. Polecam również lekturę materiałów na temat seda i wyrażeń regularnych, których lista znajduje się poniżej.

2. Materiały

Linki:

 

 
Linki sponsorowane

W celu realizacji usług i funkcji na witrynach internetowych ZUI "ELPRO" stosujemy pliki cookies. Korzystanie z witryny bez zmiany ustawień dotyczących plików cookies oznacza, że będą one zapisywane w urządzeniu wyświetlającym stronę internetową. Więcej szczegółów w Polityce plików cookies.

Akceptuję pliki cookies z tej witryny.