.. _Przetwarzanie_tekstu: Przetwarzanie plików tekstowych ++++++++++++++++++++++++++++++++++++++ Komendy omawiane w tej części zajęć: ``grep``, ``uniq``, ``sort``, ``cut``, ``paste``, ``cat`` oraz ``tr`` *Pipe* oraz przekierowanie do pliku """"""""""""""""""""""""""""""""""""""""""""" Bardzo ważnym elementem pracy w terminalu Unixowym są strumienie (ang. *pipes*). Umożliwiają one przekierowanie wyników jednej komendy do drugiej. Owa druga komenda zachowuje się tak, jakby np. wczytała owe dane wejściowe z pliku. Oto prosty przykład oparty na poleceniach z poprzedniej części: .. code-block:: bash head -20 2gb1.pdb | tail -10 cat 2gb1.pdb | head Komenda ta drukuje *drugie dziesięć* linii z pliku ``2gb1.pdb``. Jak widać, do łączenia komend stosujemy znak ``|``. Wyniki każdej komendy, który normalnie zostałby wypisany na ekranie, można zapisać do pliku. Nazywamy to przekierowaniem - nazwa chyba dość intuicyjnie oddaje zapis: .. code-block:: bash head -20 2gb1.pdb > h20 Powyższe polecenie spowoduje utworzenie pliku o nazwie ``h20``. Zaraz potem można zrobić ``tail h20`` , co powinno dać ten sam efekt, co powyższa komenda z *pipe*. **UWAGA:** poprzednia zawartość pliku ``h20`` zostanie bezpowrotnie stracona! Aby *dopisać* do pliku zamiast go *nadpisać*, używamy ``>>`` zamiast ``>``. Sam plik *2gb1.pdb* pobrać można z `tej strony `_. ``wc`` liczy linie, wyrazy i znaki """"""""""""""""""""""""""""""""""""""""""""" Komenda ``wc`` przydaje się do policzenia linii w wynikach innych komend, np: .. code-block:: bash ls *.pdb | wc odpowiada na pytanie, ile plików ``*.pdb`` jest w bieżącym katalogu. Podobnie można sprawdzić, ile razy napis "ALA" pojawił się w pliku *16pk.pdb*: .. code-block:: bash grep ALA 16pk.pdb | wc ``grep`` wybiera linie """"""""""""""""""""""""""""""""""""""""""""" Komenda ``grep`` drukuje na ekranie te linie z pliku (i tylko te), które zawierają podany fragment tekstu. Działanie komendy grep można odwrócić, aby wydrukować te linie, które nie pasują do wzorca (opcja ``-v``). Zacznijmy od wybrania wszystkich atomów (linii ``ATOM``) z pliku *3dcg.pdb*, dostępnego `pod tym adresem `_: .. code-block:: bash grep ATOM 3dcg.pdb A może interesują nas tylko atomy węgli alfa? Oznaczone są jako ``"CA"``. Każdy aminokwas ma dokładnie jeden taki atom, liczba atomów CA jest równa liczbie aminokwasów w białku. .. code-block:: bash grep CA 3dcg.pdb | wc Komenda ta niestety znajdzie też m.in. i taką linię: .. code-block:: console REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS w której również pojawia się ``CA`` (*w CAn be generated*) Aby zatem mieć pewność, że wybrane zostaną tylko te linie, na których nam zależy, trzeba wybrać linie ``ATOM`` z tych linii, które zawierają ``CA``, jak poniżej: .. code-block:: bash grep CA 3dcg.pdb | grep ATOM Podobnie możemy wybrać atomy "CA" należący do lizyny (linie zawierające fragment ``LYS``): ``grep CA 3dcg.pdb | grep LYS`` Wyniki (pierwsze pięć linii) wyglądają jak poniżej: .. code-block:: bash ATOM 92 CA LYS A 11 32.733 -0.481 8.335 1.00 35.49 C ATOM 154 CA LYS A 19 13.453 15.492 4.908 1.00 38.20 C ATOM 226 CA LYS A 28 25.964 14.436 0.101 1.00 35.42 C ATOM 290 CA LYS A 36 35.348 15.650 4.326 1.00 33.40 C ATOM 381 CA LYS A 46 19.769 2.533 -2.803 1.00 40.49 C Ponieważ fragment "CA" sąsiaduje z "LYS", można to zrobić jedną komendą: .. code-block:: bash grep "CA LYS" 3dcg.pdb | grep ATOM Należy tylko pamietać o wpisaniu odpowiedniej liczby spacji. Jeżeli wyszukiwany fragment tekstu zawiera spacje, musimy go zawrzeć w cudzysłowiach. Teraz już możemy policzyć, ile aminokwasów zawiera białko *3dcg*: .. code-block:: bash grep CA 3dcg.pdb | grep ATOM | wc ``cut`` wycina kolumny """"""""""""""""""""""""""""""""""""""""""""" Komenda ``cut`` potrafi wyciąć pionowy fragment z pliku tekstowego. To, co ma być wycięte, można zdefiniować jako kolejne znaki (liczone od lewej od 1, flaga ``-c``) oraz jako pola (flaga -f). Przez *pole* rozumiemy kolumnę tekstu (np liczb) oddzieloną od innych kolumn separatorem, np znakiem tabulacji albo spacją. Separator definiujemy flagą ``-d``. Poniżej zebrałem kilka przykładów: - ``cut -c 7 plik.txt`` - wycina siódmy znak z każdej linijki, drukuje kolunmę o szerokości jeden - ``cut -c 1-7 plik.txt`` - wycina pierwsze siedem znaków z każdej linijki - ``cut -d ',' -f 3 plik.csv`` - wycina trzecie pole; pola oddzielane są przecinkami (tzw *Comma Separated File*, CSV) .. admonition:: Ćwiczenie 1: Wytnij nazwy aminokwasów z linii ATOM pliku .pdb :class: def Wynik powinien wyglądać jak poniżej: .. code-block:: bash ALA ALA LYS LYS Sortowanie wyników """"""""""""""""""""""""""""""""""""""""""""" Plik można posortować komendą ``sort``, zupełnie jak tabelę w Excelu. - ``sort plik.txt`` - sortuje alfabetycznie linie w pliku - ``sort -f 3 plik.txt`` - sortuje alfabetycznie linie w pliku wg 3 kolumny - ``sort -f 3 -nr`` - sortuje numerycznie (bo ``-n``) linie w pliku wg 3 kolumny, wyniki na ekranie pojawiają się w kolejności odwrotnej (bo ``-r``) Unikalny podzbiór """"""""""""""""""""""""""""""""""""""""""""" Polecenie ``uniq`` wybiera jedną z wielu *identycznych* linii, ignoruje zaś pozostałe. Dodanie flagi ``-c`` powoduje wydrukowanie liczby identycznych kopii. **UWAGA**: scalane są jedynie linie następujące po bezpośrednio sobie. Wykonanie komendy ``uniq -c`` na wyniku z *Ćwiczenia 1* może dać np. następujący wynik: .. code-block:: bash 8 LEU 5 ALA 8 LEU 10 ALA 8 LEU Linia ``LEU`` pojawia się dwa razy, bo w kolumnie były dwa bloki tych linii, po 8 linii każdy. Aby policzyć ile razy powtórzyła się każda z linii w **całym tekście** należy linie **posortować** .. admonition:: Ćwiczenie 2: Ile razy każdy z aminokwasów pojawił się w pliku ``3dcg.pdb``? :class: def Użyj poznanych już poleceń aby policzyć, ile razy pojawił się każdy z aminokwasów. Pamietaj, że na pojedynczy aminokwas składa się więcej linii tekstu niż jedna. Rozwiązanie tego problemu znajdziesz powyżej. Dodatkowo ułóż wyniki malejąco od najczęściej pojawiającego się aminokwasu. Poniżej pierwsze pięć linii wyników, które powinieneś otrzymać: .. code-block:: bash 43 LEU 32 GLU 32 ALA 28 THR 26 SER Składanie w całość """"""""""""""""""""""""""""""""""""""""""""" Służy do tego komenda ``paste``, która wczytuje kilka plików i skleja je *jeden obok drugiego*, w kolejnosci od lewej do prawej. Pierwszy wymieniony na liście parametrów plik będzie po lewej, potem drugi, itd. Linie plików oddzielane są separatorem, domyślnie znakiem tabulacji. Separator można zedefiniować flagą ``-d``. W przykładzie poniżej składamy wybrane kolumny pliku w *odwrotnej kolejności*: .. code-block:: bash cut -c 1-5 dane.txt > p1 cut -c 10-15 dane.txt > p2 paste -d ' ' p2 p1 > wynik.txt Jeżeli zajdzie potrzeba sklejenia plików *jednego pod drugim*, należy skorzystać z komendy ``cat`` (od *concatenate*): ``cat plik1.txt plik2.txt`` ``tr`` podmienia znaki """"""""""""""""""""""""""""""""""""""""""""" Z powyższych przykładów widać, że przetwarzanie plików w systemie Unix odbywa się *linijka po linijce*. Co zrobić, aby przetwarzać wyraz po wyrazie? Czasem najłatwiej jest umieścić wyrazy w oddzielnych liniach, a następnie skorzystać ze znanych już rozwiązań. Komenta ``tr`` zamienia dowolny znak na inny dowolny znak w całym tekście. Polecenie to można wykorzystać do podmiany spacji na znak nowej linii (*enter*) lub na odwrót: .. code-block:: bash tr ' ' '\n' < jednalinia.txt > wielelinii.txt tr ' ' '\n' < wielelinii.txt > jednalinia.txt Polecenie ``tr`` może w jednym przebiegu wykonać kilka podmian, np: .. code-block:: bash tr 'ABC' 'abc' < wyrazy.txt > wynik.txt zamieni w całym tekście wielkie litery A, B oraz C na ich małe odpowiedniki. Wielkie litery D itd. nie zostaną podmienione. Zatem jak podmienić wszystkie wielkie na małe? Można oczywiście pracowicie wpisać odpowienie litery, można też skorzystać z predefiniowanych klas znaków: .. code-block:: bash tr '[:upper:]' '[:lower:]' < wyrazy.txt > wynik.txt **Uwaga**: ``tr`` nie zamienia wyrazów! Polecenie ``tr 'Jacek' 'Agata' < plik.txt`` nie podmieni imion. .. admonition:: Zadanie 1: Jakiego wyrazu J.R.R Tolkien używa najczęściej w swojej książce? :class: def W pliku *lort1.txt* znajduje się pierwszy tom *,,Władcy Pierścieni''* - w formacie tekstowym. Policz, ile razy powtarza się każdy z wyrazów. Wydrukuj 20 najczęściej powtarzających się słów. Pamiętaj, aby zamienić wielkie litery na małe, dzięki czemu *,,Then''* zostanie policzone wspólnie z *,,then''*. Usuń też znaki interpunkcyjne, aby *,,him.''* było tym samym wyrazem, co *,,him''*