Praca z plikami tekstowymi w linii komend

← Spis treści

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:

http://ggoralski.pl/files/filogenetyka-data/Orobanchaceae-trnL-trnF-aligned.fasta

Liczenie zawartości i wyświetlanie części pliku - polecenia wc, head, tail.

Wykonaj polecenie:

$: wc Orobanchaceae-trnL-trnF-aligned.fasta 
  18   18 9254 Orobanchaceae-trnL-trnF-aligned.fasta

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:

http://ggoralski.pl/files/filogenetyka-data/Orobanchaceae-trnL-trnF-aligned.aln

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:

$: wc *
  233   490 17672 Orobanchaceae-trnL-trnF-aligned.aln
   18    18  9254 Orobanchaceae-trnL-trnF-aligned.fasta
  251   508 26926 razem

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:

$: head Orobanchaceae-trnL-trnF-aligned.aln 
CLUSTAL 2.1 multiple sequence alignment


KY484464_O._teucrii                AGTTATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAGAGAAA-GGGC
KY484493_O._flava                  AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAGAAAAA-GGGC
KY484489_O._mayeri                 AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAATAAAAA-GGGC
KY484471_O._kochii                 AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAATAAAAA-GGGC
KY484474_O._elatior                AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAATAAAAA-GGGC
KU238865_O._coerulescens           AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAGAAAAA-GGGC
KY484502_P._ramosa                 GGTGATAAC-TTTCAAATTCAGAGAAACTCCGGAATTAATAAAAACGGGC
$: tail Orobanchaceae-trnL-trnF-aligned.aln 
KY484464_O._teucrii                AAATG
KY484493_O._flava                  AAATG
KY484489_O._mayeri                 AAATG
KY484471_O._kochii                 AAATG
KY484474_O._elatior                AAATG
KU238865_O._coerulescens           GAATG
KY484502_P._ramosa                 GAATG
KY484503_P._purpurea               GAATG
KX524675_Lindenbergia_siniaca      GAATG
                                    ****

Liczbę wyświetlanych linii można dostosować używając flagi -n:

$: head -n 5 Orobanchaceae-trnL-trnF-aligned.aln 
CLUSTAL 2.1 multiple sequence alignment


KY484464_O._teucrii                AGTTATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAGAGAAA-GGGC
KY484493_O._flava                  AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAGAAAAA-GGGC
$: tail -n 5 Orobanchaceae-trnL-trnF-aligned.aln 
KU238865_O._coerulescens           GAATG
KY484502_P._ramosa                 GAATG
KY484503_P._purpurea               GAATG
KX524675_Lindenbergia_siniaca      GAATG
                                    ****

grep - wyszukiwanie w pliku tekstowym

Narzę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:

$: grep Lindenbergia Orobanchaceae-trnL-trnF-aligned.fasta 
>KX524675_Lindenbergia_siniaca

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:

$: grep Lindenbergia *          

Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      AGTGATAAC-TTTCAAATTCAGAGAAACCCCGGAATTAAAAAAGG-GGGC
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      AATCCTGAGCCAAATCCTGT-----TTTCTCAAAACAAA-G--------A
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      C-AAAAATAAAGGATAGGTGCAGAGACTCAACGGAAGCTGTTCTAAC---
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      -AAATGGAGTTGATTGCGCCGGTAGAGGAATCTTTCCATCGAAACTTCGG
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      AAAGGATGAAGGATAAACGTATCTATTGAATACTATATCAAATTATTAAT
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      GATATCAAATTATTAATGATGGCCCGAATCTGTATCTGTATTTTT---TA
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      ATTTTAATATGAAAAATGGAAAAGTTAGTGTGAATTGATTCCATATTGAA
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      GAAAGAATCGAATATTCATT-------CATCAAATCATTCACTCCACAGT
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      CCGATAGATC-----TTTTAAAGAATTGATTAATCGGATGAGAATAAAGA
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TAGAGTCCCATTC----------TACATGTCAATACCGGCAACAATGAAA
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TTTATAGTAAGAGGAAAATCCGTCGACTTTAAAAATCGTGAGGGTTCAAG
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TCCCTCTATCCCCAA---AAAAAGTCTATTTTACTTCCA-----------
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      -----------AAATATTTAGCCTATTTCA-----------------TTT
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TCG-TTAGCGGTTCCAAATTCCTT--TTCTGATTC--TTTGACA--AACG
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TATTGGGGCGT------------------AAATGACTTT-CTCTTATCAC
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      ATGTG------ATATAGAATACACATCCAAATTCAGCAAGGAATTCCTAT
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      TTGAATG------ATTCAGAATCAATAACATTACTC-AT-ACTGAAACTT
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      AGA---AAGTTCGTCTTTTTGAAGATCCAATAAATTACAGGATTTGGAGA
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      AAACTTTGTAATCTTCCCCA--TCCCTTTAATTGACATAGAGCCCAGTC-
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      ---ATCTAAT--AAAATCA------GGATGGGAATGGGATTATACATTGG
Orobanchaceae-trnL-trnF-aligned.aln:KX524675_Lindenbergia_siniaca      GAATG
Orobanchaceae-trnL-trnF-aligned.fasta:>KX524675_Lindenbergia_siniaca

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:

$: grep > Orobanchaceae-trnL-trnF-aligned.fasta 
Składnia: grep [OPCJA]... WZORZEC [PLIK] ...
Napisz „grep --help” żeby dowiedzieć się więcej.

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:

$: grep ">" Orobanchaceae-trnL-trnF-aligned.fasta
>KY484464_O._teucrii
>KY484493_O._flava
>KY484489_O._mayeri
>KY484471_O._kochii
>KY484474_O._elatior
>KU238865_O._coerulescens
>KY484502_P._ramosa
>KY484503_P._purpurea
>KX524675_Lindenbergia_siniaca

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.

$: grep ">" Orobanchaceae-trnL-trnF-aligned.fasta | wc -l
9

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'':

$: grep -v Lindenbergia Orobanchaceae-trnL-trnF-aligned.fasta | grep ">"
>KY484464_O._teucrii
>KY484493_O._flava
>KY484489_O._mayeri
>KY484471_O._kochii
>KY484474_O._elatior
>KU238865_O._coerulescens
>KY484502_P._ramosa
>KY484503_P._purpurea

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:

$: grep -v Lindenbergia Orobanchaceae-trnL-trnF-aligned.fasta | grep ">" | sort
>KU238865_O._coerulescens
>KY484464_O._teucrii
>KY484471_O._kochii
>KY484474_O._elatior
>KY484489_O._mayeri
>KY484493_O._flava
>KY484502_P._ramosa
>KY484503_P._purpurea

Można oczywiście uzyskaną posortowaną listę nazw sekwencji przekazać do pliku:

$: grep -v Lindenbergia Orobanchaceae-trnL-trnF-aligned.fasta | grep ">" | sort > posortowane.txt

Wykonaj powyższe polecenie i sprawdź zawartość pliku posortowane.txt.

xargs - przekazanie argumentów do kolejnego polecenia

Narzędzie xargs pozwala przekazać kolejnemu poleceniu argumenty otrzymane ze standardowego wejścia, czyli np. przez potok. Najłatwiej pokazać to na przykładzie:

ls *.fasta | xargs cat > wszystkie.fasta

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ę:

cat *.fasta > wszystkie.fasta

ale jak się później przekonamy, nie zawsze tak łatwo jest pominąć xargs i program ten bywa bardzo pożyteczny.

sed - przetwarzanie tekstu

Kolejne 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:

sed 's/szukany/zmieniony/g' plik

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ń.

$: echo "ATCTTGGATCG" | sed 's/T/U/g'
AUCUUGGAUCG

Kilka przykładów, wykorzystamy utworzony powyżej plik posortowane.txt, najpierw sprawdźmy co zawiera:

$: more posortowane.txt 

>KU238865_O._coerulescens
>KY484464_O._teucrii
>KY484471_O._kochii
>KY484474_O._elatior
>KY484489_O._mayeri
>KY484493_O._flava
>KY484502_P._ramosa
>KY484503_P._purpurea

Zamiana znaków '_' na spacje:

$: sed 's/_/ /g' posortowane.txt

>KU238865 O. coerulescens
>KY484464 O. teucrii
>KY484471 O. kochii
>KY484474 O. elatior
>KY484489 O. mayeri
>KY484493 O. flava
>KY484502 P. ramosa
>KY484503 P. purpurea

Usuwane znaku >, ponieważ występuje on tylko raz w linii, opcja g jest zbędna:

$: sed 's/>//' posortowane.txt 

KU238865_O._coerulescens
KY484464_O._teucrii
KY484471_O._kochii
KY484474_O._elatior
KY484489_O._mayeri
KY484493_O._flava
KY484502_P._ramosa
KY484503_P._purpurea

Połączmy teraz dwa powyższe i zmieńmy skróty P. oraz O. na pełne nazwy rodzajowe:

$: sed 's/>//' posortowane.txt | sed 's/_/ /g' | sed 's/O\./Orobanche/' | sed 's/P\./Phelipanche/'

KU238865 Orobanche coerulescens
KY484464 Orobanche teucrii
KY484471 Orobanche kochii
KY484474 Orobanche elatior
KY484489 Orobanche mayeri
KY484493 Orobanche flava
KY484502 Phelipanche ramosa
KY484503 Phelipanche purpurea

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 >:

$: sed 's/>//' posortowane.txt | sed 's/_/ /g' | sed 's/O\./Orobanche/' | sed 's/P\./Phelipanche/' > zmieniony.txt

Teraz można wykonać polecenie:

$: mv zmieniony.txt posortowane.txt

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):

$: sed -i 's/>//;s/_/ /g;s/O\./Orobanche/;s/P\./Phelipanche/' posortowane.txt

Można też wykonać kolejno operacje:

$: sed -i 's/>//' posortowane.txt
$: sed -i 's/_/ /g' posortowane.txt
$: sed -i 's/O\./Orobanche/' posortowane.txt
$: sed -i 's/P\./Phelipanche/' posortowane.txt

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.

$: more posortowane.txt 

KU238865 Orobanche coerulescens
KY484464 Orobanche teucrii
KY484471 Orobanche kochii
KY484474 Orobanche elatior
KY484489 Orobanche mayeri
KY484493 Orobanche flava
KY484502 Phelipanche ramosa
KY484503 Phelipanche purpurea

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:

$: sed 's/^[[:alnum:]]\+[[:space:]]//' posortowane.txt

Orobanche coerulescens
Orobanche teucrii
Orobanche kochii
Orobanche elatior
Orobanche mayeri
Orobanche flava
Phelipanche ramosa
Phelipanche purpurea

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?

$: more posortowane.txt 

KU238865 Orobanche coerulescens
KY484464 Orobanche teucrii
KY484471 Orobanche kochii
KY484474 Orobanche elatior
KY484489 Orobanche mayeri
KY484493 Orobanche flava
KY484502 Phelipanche ramosa
KY484503 Phelipanche purpurea

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:

$: sed 's/^[[:alnum:]]\+[[:space:]]//' posortowane.txt
  • ^ 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:

$: sed 's/^\([[:alnum:]]\+[[:space:]]\)\(.*\)/\2 \1/' posortowane.txt

Orobanche coerulescens KU238865 
Orobanche teucrii KY484464 
Orobanche kochii KY484471 
Orobanche elatior KY484474 
Orobanche mayeri KY484489 
Orobanche flava KY484493 
Phelipanche ramosa KY484502 
Phelipanche purpurea KY484503

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:

$: sed "/^>/ s/A/0/g" plik.fasta

Zamieni znaki A na 0 w liniach, które zaczynają się od >.

Z kolei polecenie:

$: sed "/^>/! s/A/0/g" plik.fasta

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:

sed -i "1s/^/Tytuł dzieła\n/" plik.txt

Aby usunąć linie, w których znajduje się dany wzorzec stosujemy następującą komendę:

sed '/wzorzec/d' plik

Na przykład poniższa komenda usunie wszystkie linie z opisami sekwencji z pliku sekwencje.fasta

sed -i '/^>/d' sekwencje.fasta

tr - zmiana i usuwanie znaków

Program tr ma podobne zastosowanie do sed-a, specjalizuje się jednak w zamianie pojedynczych znaków.

Używamy go w ten sposób:

tr opcje znaki1 znaki2

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 -

$: echo "AGGC*TT" | tr "*" "-"

AGGC-TT

Usunięcie znaków -. Tak można łatwo usunąć z sekwencji znaki oznaczające indele.

$: echo "AG--GC-TT" | tr -d "-"

AGGCTT

Zamiana A na T, C na G, G na C oraz T na A.

$: echo "AGGCTT" | tr "ACGT" "TGCA" 

TCCGAA

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:

CGACCAGATTACGGGGCCCATTA
CGAGACATTTATATACGATATAG
AAATTTCGCGCGCAGATAGCATA

Teraz utworzymy dla tych krótkich sekwencji sekwencje komplementarne:

tr "ACGT" "TGCA" < sekwencje.txt > sekwencje_komplementarne.txt

albo

cat sekwencje.txt | tr "ACGT" "TGCA" > sekwencje_komplementarne.txt

Otrzymujemy plik sekwencje_komplementarne.txt:

GCTGGTCTAATGCCCCGGGTAAT
GCTCTGTAAATATATGCTATATC
TTTAAAGCGCGCGTCTATCGTAT

Teraz połączmy te sekwencje w jedną, długą. W tym celu usuniemy oznaczający znak nowej linii.

tr -d "\n" < sekwencje_komplementarne.txt > polaczona_sekwencja_komplementarna.txt

Tu też oczywiście można też użyć komendy cat i znaku |:

cat sekwencje_komplementarne.txt| tr -d "\n" > polaczona_sekwencja_komplementarna.txt

Plik wynikowy, zgodnie z założeniem, posiada jedną długą sekwencję:

GCTGGTCTAATGCCCCGGGTAATGCTCTGTAAATATATGCTATATCTTTAAAGCGCGCGTCTATCGTAT

rev - odwracanie łańcucha znaków

Bardzo prostym, ale użytecznym narzędziem jest rev (od reverse), który odwraca łańcuch znaków.

$: echo "ACGTTT" | rev

TTTGCA

Teraz można sekwencję w pliku polaczona_sekwencja_komplementarna.txt także odwrócić. W efekcie otrzymamy sekwencję komplementarną, odwróconą.

cat polaczona_sekwencja_komplementarna.txt | rev > polaczona_sekwencja_komplementarna_odwrocona.txt

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:

cat sekwencja.txt | tr "ACGT" "TGCA" | tr -d "\n" | rev > sekwencja_RC.txt

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:

http://ggoralski.pl/files/filogenetyka-data/atp6-samples.fasta`

Najpierw uzyskajmy opisy sekwencji:

$: grep ">" atp6-samples.fasta 
>KY492922.1 Dendropicos elliotii isolate DA07 ATP6 (ATP6) gene, partial cds; mitochondrial
>KY492921.1 Dendropicos stierlingi isolate ZMUC74329 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492920.1 Dendropicos poecilolaemus isolate ZMUC72915 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492919.1 Campethera punctuligera isolate ZMUC56174 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492918.1 Campethera cailliautii isolate ZMUC56172 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492917.1 Dendropicos fuscescens isolate Z34 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492916.1 Campethera cailliautii isolate W45 ATP6 (ATP6) gene, complete cds; mitochondrial
>KY492915.1 Chloropicus xantholophus isolate MNHN2005922 ATP6 (ATP6) gene, complete cds; mitochondrial
....

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ć?

$: grep ">" atp6-samples.fasta \
| sed 's/^>[[:alnum:]]\+\.[[:digit:]][[:space:]]\([[:alpha:]]\+\).\+/\1/'

Dendropicos
Dendropicos
Dendropicos
Campethera
Campethera
Dendropicos
Campethera
Chloropicus
Campethera
Dendropicos
...

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:

$: grep ">" atp6-samples.fasta | \
sed 's/^>[[:alnum:]]\+\.[[:digit:]][[:space:]]\([[:alpha:]]\+\).\+/\1/' \
| uniq

Dendropicos
Campethera
Dendropicos
Campethera
Chloropicus
Campethera
Dendropicos
Campethera
Ipophilus
...

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.

grep ">" atp6-samples.fasta | \
sed 's/^>[[:alnum:]]\+\.[[:digit:]][[:space:]]\([[:alpha:]]\+\).\+/\1/' \
| sort | uniq

Campethera
Chloropicus
Cooperia
Dendropicos
Ipophilus
Paracoccidioides
Pocillopora

Zadanie: policz ile sekwencji i ile różnych nazw rodzajowych znajduje się w pliku

Last updated