Praca z plikami tekstowymi w linii komend
Praca z plikami tekstowymi w linii komend
Dlaczego to takie ważne?
Jak już wspominałem, praca bioinformatyka to w dużej mierze, o ile nie przede wszystkim praca z plikami tekstowymi. W poprzedniej lekcji pokazałem jak umieścić tekst w pliku przy pomocy operatorów >
oraz >>
a także jak wyświetlić zawartość pliku używając komend more
, less
i cat
. Linux oferuje jednak znacznie więcej narzędzi pozwalających na efektywną pracę z plikami tekstowymi bez uciekania się do pomocy edytorów tekstu (na które też przyjdzie pora). Poniżej pokażę wybrane możliwości niektórych z nich. Warto jednak samodzielnie poszerzyć wiedzę na ten temat, ponieważ potrafią znacznie usprawnić i przyspieszyć pracę.
W terminalu utwórz katalog Pliki_tekstowe
i wejdź do niego. Używając polecenia curl
lub wget
pobierz plik:
Liczenie zawartości i wyświetlanie części pliku - polecenia wc
, head
, tail
.
wc
, head
, tail
.Wykonaj polecenie:
Komenda wc
wyświetla liczbę linii, słów oraz wielkość liczoną w bajtach podanego pliku. Podając odpowiednie flagi, można uzyskać tylko wybrane dane (sprawdź wc --help
), co później wykorzystamy. W przypadku pobranego pliku liczba linii i słów jest taka sama (18) ponieważ w opisach i sekwencjach nie występują spacje a sekwencje zostały umieszczone każda w jednej linii. Sprawdź zatem inny plik:
Zawiera on dopasowane sekwencje zapisane w formacie CLUSTAL
. Zobacz jaka jest zawartość pliku a następnie sprawdź ile ma linii i słów.
Polecenie wc
może odczytywać dane z wielu plików jednocześnie:
Nie zawsze konieczne jest przeglądanie całego pliku. Czasem chcemy po prostu zobaczyć jak wygląda jego początek i koniec. Wtedy przychodzą nam z pomocą polecenia head
i tail
, które jak łatwo zgadnąć wyświetlają odpowiednio początek i koniec pliku:
Liczbę wyświetlanych linii można dostosować używając flagi -n
:
grep
- wyszukiwanie w pliku tekstowym
grep
- wyszukiwanie w pliku tekstowymNarzędzie grep
z pewnością należy do najbardziej użytecznych programów do pracy z plikami tekstowymi. Służy do wynajdywania w plikach danego ciągu znaków.
W katalogu z pobranymi (patrz wyżej) plikami wykonaj polecenie:
W podanym pliku został znaleziony ciąg znaków Lindenbergia
a następnie linia w którym się znajdował została wyświetlona. Jeśli znaleziony fragment nie wyświetla się w innym kolorze niż pozostała część linii to można to uzyskać podając opcję --color=AUTO
, np. grep --color=AUTO Lindenbergia Orobanchaceae-trnL-trnF-aligned.fasta
.
Można przeszukać od razu wiele plików np. używając znaków wieloznacznych, uzyskamy także informację w jakim pliku znaleziono dopasowanie:
Jeśli chcemy przeszukać pliki w danym katalogu, należy użyć opcji -r
, np.: grep -r Lindenbergia SEKWENCJE
.
Narzędzia grep można użyć na przykład do sprawdzenia ile sekwencji znajduje się w pliku fasta
. W tym celu należy znaleźć i policzyć linie zawierające znak >
. Tu jednak czyha pewna pułapka. Najbardziej oczywistą komendą wydaje się: grep > Orobanchaceae-trnL-trnF-aligned.fasta
ale jej wynik będzie taki:
Po pierwsze polecenie ewidentnie nie zrobiło tego czego po nim oczekiwaliśmy a po drugie jeśli teraz spróbujemy wyświetlić zawartość pliku Orobanchaceae-trnL-trnF-aligned.fasta
to okaże się, że jest pusty. Dlaczego?
Przypomnijmy sobie, że operator >
służy do przekazania tekstu do pliku. Zatem polecenie grep > Orobanchaceae-trnL-trnF-aligned.fasta
uruchomiło polecenie grep
(z nieprawidłową składnią) a wynik jego działania zapisało w pliku, w którym chcieliśmy szukać znaków >
, wymazując jego poprzednią zawartość. Jest to bardzo łatwy do popełnienia błąd, który może się skończyć utratą wyników pracy! Jak więc należy prawidłowo wyszukać znaku >
? Umieszczając go w cudzysłowach:
Zadanie: Zastanów się, co trzeba zrobić, żeby uzyskać nazwy sekwencji w osobnym pliku?
No dobrze, teraz możemy policzyć wyświetlone linie ale wolelibyśmy, żeby komputer sam je policzył. Co prawda istnieje odpowiednia opcja programu grep
, która to robi (znajdź ją), ale jest to dobra okazja, żeby pokazać w jaki sposób można połączyć różne polecenia tak aby wykonały razem zadanie.
Potoki, czyli łączymy polecenia.
Chcemy policzyć linie, w których znajduje się znak >
. Mamy do dyspozycji jedno narzędzie, które wyszukuje odpowiednie linie (grep
) i drugie, które liczy linie (wc
). Trzeba je zatem odpowiednio połączyć w jeden ,,taśmociąg''. Wykorzystamy do tego potoki (ang. pipe) - wynik działania grep
(strumień) zostanie skierowany do wc
. Do łączenia w ten sposób poleceń służy operator |
. Polecenia wc
użyjemy z flagą -l
, która zwraca liczbę linii.
Wiemy, że w pliku mamy 9 sekwencji.
Teraz poznamy kolejną opcję -v
, która pozwala ,,odwrócić'' dopasowanie, czyli zwrócić linie, w których nie występuje dopasowanie i połączymy dwa polecenia grep
tak, aby uzyskać listę próbek, które nie zawierają ciągu ,,Lindenbergia'':
Jak widać, w drugim wywołaniu plecenia grep
nie podaliśmy nazwy pliku, tekst do przeanalizowania został przekazany za pomocą potoku.
Wynik możemy przekazać dalej, na przykład do polecenia sort
, które jak nazwa wskazuje sortuje linie tekstu:
Można oczywiście uzyskaną posortowaną listę nazw sekwencji przekazać do pliku:
Wykonaj powyższe polecenie i sprawdź zawartość pliku posortowane.txt
.
xargs
- przekazanie argumentów do kolejnego polecenia
xargs
- przekazanie argumentów do kolejnego poleceniaNarzędzie xargs
pozwala przekazać kolejnemu poleceniu argumenty otrzymane ze standardowego wejścia, czyli np. przez potok. Najłatwiej pokazać to na przykładzie:
Najpierw mamy polecenie ls *fasta
, które zwraca listę plików o przedłużeniu fasta
znajdujących się w bieżącym katalogu. Jest ona przekazywana przez potok do polecenia xargs
, które przekazuje je poleceniu cat
jako kolejne argumenty. Jak wiemy polecenie cat
zwraca zawartość pliku, którego nazwa jest argumentem do standardowego wyjścia, którym może być ekran, ale w tym przypadku, przekierowujemy ją do pliku wszystkie.fasta
. Tak więc całe polecenie umieszcza zawartość wszystkich plików fasta
w pliku wynikowym. W tym przypadku można by było po prostu wykonać komendę:
ale jak się później przekonamy, nie zawsze tak łatwo jest pominąć xargs
i program ten bywa bardzo pożyteczny.
sed
- przetwarzanie tekstu
sed
- przetwarzanie tekstuKolejne bardzo użyteczne narzędzie to sed
. Pozwala na edycję strumienia danych. Jedną z zalet używania tego typu programów jest możliwość uzyskiwania i modyfikacji danych z plików bez konieczności ich otwierania od razu w całości, jak to ma miejsce w edytorach tekstu. Nie ma to wielkiego znaczenia w przypadku niewielkich plików ale na przykład pliki uzyskiwane przy sekwencjonowaniu genomów mogą mieć wielkość wielu gigabajtów co w znacznym stopniu utrudnia pracę nad nimi w edytorach tekstu. Nawet jednak dla małych plików praca z linii komend może być po prostu znacznie szybsza.
Prosty schemat użycia sed
wygląda tak:
W pliku plik
zmieniane są wszystkie ciągi znaków szukany
na zmieniony
. Bez opcji g
(po trzecim ukośniku) zmienione zostanie tylko pierwsze wystąpienie szukanego ciągu w linii. Zamiast pliku można użyć strumienia danych z innych poleceń.
Kilka przykładów, wykorzystamy utworzony powyżej plik posortowane.txt
, najpierw sprawdźmy co zawiera:
Zamiana znaków '_' na spacje:
Usuwane znaku >
, ponieważ występuje on tylko raz w linii, opcja g
jest zbędna:
Połączmy teraz dwa powyższe i zmieńmy skróty P.
oraz O.
na pełne nazwy rodzajowe:
Zauważ, że zamiast napisać s/O./Orobanche/
napisałem s/O\./Orobanche/
. Co prawda w tym przypadku oba warianty zwrócą taki sam wynik, ale sposób ich działania jest nieco odmienny, o czym za chwilę.
Wynik działania sed
często chcemy zapisać w pliku. Można w tym celu użyć znaku >
:
Teraz można wykonać polecenie:
Jeśli chcemy bezpośrednio zmienić plik oryginalny, należy użyć opcji -i ale wtedy nie użyjemy potoków, możemy natomiast zgrupować formuły zmian razem oddzielając je średnikami (jeśli to nie działa spróbuj dodać opcję -e
):
Można też wykonać kolejno operacje:
Należy uważać ze zmianą oryginalnego pliku, lepiej najpierw sprawdzić czy wpisywana formuła edycji działa prawidłowo a dopiero później użyć opcji -i
. Oczywiście warto też mieć zabezpieczoną kopię oryginalnego pliku.
Wyrażenia regularne
Wyrażenia regularne są bardzo użyteczne w bioinformatyce, ponieważ są potężnym narzędziem ułatwiającym pracę z plikami tekstowymi i strumieniami tekstu czy ogólniej z ciągami znaków. Dzięki nim można opisać z różnym stopniem ogólności ciągi znaków, czy ich kategorie aby później je wyświetlić, usunąć czy zmodyfikować. Wykorzystuje się je w takich narzędziach jak grep
, sed
i wielu innych z dobrymi edytorami tekstu włącznie (np. vim
).
Przyjrzyjmy się ponownie zmodyfikowanemu plikowi posortowane.txt
.
Przypuśćmy, że chcemy uzyskać jedynie listę organizmów, bez numerów GenBank-u. Można by je po kolei usuwać, ale znaczne wygodniej będzie użyć wyrażeń regularnych:
Zanim wyjaśnię jak i dlaczego to działa, trochę teorii.
W wyrażeniach regularnych możemy stosować znaki rozumiane dosłownie (litery, cyfry, spacje, niektóre inne znaki) oraz znaki specjalne ($
, *
, .
, [
, \
, oraz ^
) i wyrażenia, które pozwalają na przykład opisać kategorie znaków, ich liczbę, położenie itp. Na przykład ATG
oznacza ciąg ATG
ale [ATG]
oznacza A
lub T
lub G
. Specjalne znaczenie ma znak \
, który zmienia znaczenie następnego znaku - na przykład oznacza, że następujący po nim znak specjalny powinien być rozumiany dosłownie albo, że zwykły znak ma znaczenie specjalne.
W poniższej tabeli znajdują się niektóre przykłady:
Wyrażenie
Znaczenie
Przykład
Znaczenie przykładu
*
zero lub więcej wystąpień wyrażenia
T*
zero lub więcej liter T
\+
jedno lub więcej wystąpień wyrażenia
T\+
jedna lub więcej litera T
\?
zero lub jedno wystąpień wyrażenia
T\?
zero lub jedna litera T
\{i\}
dokładnie i
wystąpień wyrażenia
T\{3\}
trzy znaki T
\{i,j\}
pomiędzy i
a j
wystąpień wyrażenia
T\{3,5\}
pomiędzy 3 a 5 znaków T
\{i,\}
i
lub więcej wystąpień wyrażenia
T\{3,\}
przynajmniej 3 znaki T
.
jakikolwiek znak
.\{3\}
trzy dowolne znaki
^
początek linii
^T
znak T
występujący na początku linii
$
koniec linii
T$
znak T
na końcu linii
[znaki]
jakikolwiek znak z zestawu znaków
[TGA]
T
lub G
lub A
[x-y]
jakikolwiek znak z zakresu x do y (litery, cyfry)
[A-Z]
duża litera
[a-z 0-9]
mała litera lub cyfra
[^znaki]
jakikolwiek znak z poza zestawu znaków
[^TGA]
jakikolwiek znak oprócz T
, G
i A
\znak_specjalny
znak specjalny ($
, *
, .
, [
, \
, ^
) rozumiany dosłownie
\^
znak ^
(a nie początek linii)
\(wyrażenie\)
wyrażenie grupujące, dopasowany łańcuch można później wykorzystać, np. wstawiając go w inne miejsce
znak nowej linii
znak tabulatora
[[:alnum:]]
znak alfanumeryczny (litery lub cyfry)
[[:alpha:]]
litera
[[:digit:]]
cyfra
[[:blank:]]
spacja lub tabulator
[[:space:]]
znak odstępu (w tym nowej linii)
Zauważ, że znaczenie znaku ^
zmienia się w zależności od kontekstu - oznacza on początek linii lub negację zakresu znaków.
Wróćmy teraz do pliku posortowane.txt
i zastanówmy się jak można opisać numery GenBank-u?
Jest to ciąg znaków zaczynający się na początku linii, zawierający litery i cyfry (znali alfanumeryczne) po którym występuje spacja (jeden ze znaków odstępu).
Teraz poprzednio użyte wyrażenie powinno być bardziej zrozumiałe:
^
początek linii[[:alnum:]]\+
jeden lub więcej znaków alfanumerycznych[[:space:]]
znak odstępu.
Zadanie: Spróbuj usunąć numery GenBank-u używając innego wyrażenia.
Po przejrzeniu powyższej tabeli powinno być jasne, dlaczego powyżej zamiast napisać s/O./Orobanche/
napisałem s/O\./Orobanche/
. Kropka oznacza jakikolwiek znak, ponieważ także oznacza kropkę oba wyrażenia zadziałają w tym przypadku (!) tak samo, ale jeśli chcemy być pewni, że dopasujemy znak .
, to powinniśmy użyć przed nim znaku \
, co spowoduje, że kropka zostanie odczytana dosłownie.
Zamieszczone w tabeli wyrażenie \(wyrażenie\)
zapewne wydaje się niejasne. Pokażę zatem na przykładzie jak może być wykorzystane. Tym razem zadaniem będzie przeniesienie numeru GenBank-u na koniec linii. Można to zrobić tak:
Powyżej wykorzystałem dwa wyrażenia grupujące. Pierwszy z nich obejmuje dopasowanie numeru GenBank-u (oraz spację), drugie pozostałą część tekstu (.*
oznacza zero lub więcej dowolnych znaków. Po drugim ukośniku odwołuję się do wcześniej znalezionych dopasowań: \1
oznacza pierwsze dopasowanie, \2
drugie dopasowanie. Umieszczając je w kolejności \2 \1
umieściłem pierwsze dopasowanie po drugim.
Zamianę można ograniczyć do linii, w których znajduje się inne dopasowanie. Na przykład:
Zamieni znaki A
na 0
w liniach, które zaczynają się od >
.
Z kolei polecenie:
Dokona zamiany w liniach, które nie rozpoczynają się od >
.
Jeśli przed s
w poleceniu umieścimy liczbę, będzie się ono odnosiło do linii w pliku o podanym numerze. Możemy np. w ten sposób dodać tekst w pierwszej linii w pliku plik.txt
:
Aby usunąć linie, w których znajduje się dany wzorzec stosujemy następującą komendę:
Na przykład poniższa komenda usunie wszystkie linie z opisami sekwencji z pliku sekwencje.fasta
tr
- zmiana i usuwanie znaków
tr
- zmiana i usuwanie znakówProgram tr
ma podobne zastosowanie do sed
-a, specjalizuje się jednak w zamianie pojedynczych znaków.
Używamy go w ten sposób:
znaki1
- to zestaw znaków które zmieniamy znaki2
- to zestaw znaków na które zmieniamy
Pokażę to na kilku przykładach.
Zamiana *
na -
Usunięcie znaków -
. Tak można łatwo usunąć z sekwencji znaki oznaczające indele.
Zamiana A
na T
, C
na G
, G
na C
oraz T
na A
.
W ten sposób można otrzymać łatwo sekwencję komplementarną. Zauważ, że powyższa komenda nie zmienia sekwencji ACGT
na TGCA
, ale podmienia poszczególne znaki.
tr
nie ma możliwości bezpośredniej modyfikacji pliku, dlatego jeśli chcemy zmienić plik, użyjemy znaków przekierowania <
do pliku wejściowego i >
dla pliku wyjściowego.
Utwórz plik sekwencje.txt
o zawartości:
Teraz utworzymy dla tych krótkich sekwencji sekwencje komplementarne:
albo
Otrzymujemy plik sekwencje_komplementarne.txt
:
Teraz połączmy te sekwencje w jedną, długą. W tym celu usuniemy oznaczający znak nowej linii.
Tu też oczywiście można też użyć komendy cat
i znaku |
:
Plik wynikowy, zgodnie z założeniem, posiada jedną długą sekwencję:
rev
- odwracanie łańcucha znaków
rev
- odwracanie łańcucha znakówBardzo prostym, ale użytecznym narzędziem jest rev
(od reverse), który odwraca łańcuch znaków.
Teraz można sekwencję w pliku polaczona_sekwencja_komplementarna.txt
także odwrócić. W efekcie otrzymamy sekwencję komplementarną, odwróconą.
Cały proces łączenia przekształcania sekwencji w odwróconą i komplementarną można zmieścić w ,,jednolinijkowcu'' używając potoków i przekierowania:
uniq
- usuwanie powtórzeń
uniq
- usuwanie powtórzeńPolecenie uniq
pozwala na usuwanie powtarzających się linii. Na przykład chcielibyśmy otrzymać listę rodzajów z taksonów znajdujących się w pliku fasta
ale tak, aby każda nazwa występowała tylko raz.
Pobierz plik:
Najpierw uzyskajmy opisy sekwencji:
Jak widać opisy są nieco bardziej złożone niż w poprzednio używanym pliku, ponadto jest ich więcej (powyżej widać tylko początek listy).
Teraz trzeba wyodrębnić nazwy rodzajowe. W naszym pliku jest to drugi ciąg znaków alfanumerycznych. Zastanów się jak go uzyskać?
Tym razem wykorzystałem jedno wyrażenie grupujące, odpowiadające nazwie rodzajowej, obejmujące ciąg znaków alfanumerycznych. Przed nim znajduje się numer GenBank-kowy sekwencji (znali alfanumeryczne, kropka, cyfra) ze spacją, a po nim pozostałe znaki w linii. Dopasowana całość (czyli cała linia) zostaje zamieniona na wyrażenie, które znalazło się w wyrażeniu grupującym (\1
), czyli na nazwę rodzaju.
Szkopuł w tym, że nazwy te wyświetlają się wielokrotnie, a chcielibyśmy mieć listę rodzajów, taką w której każda występowałaby tylko raz. Dodajmy zatem polecenie uniq
:
Efekt jest nie do końca zgodny z oczekiwaniami. Co prawda duplikaty zostały usunięte, ale tylko wtedy gdy znajdowały się bezpośrednio po sobie. Tak właśnie działa uniq
. Wykorzystajmy zatem polecenie, które sortuje linie, czyli sort
wtedy wszystkie takie same linie znajdą się bezpośrednio przy sobie.
Zadanie: policz ile sekwencji i ile różnych nazw rodzajowych znajduje się w pliku
Last updated