Twitter: @grzegg
Kategoria: bioinformatyka, Tagi: - - - - - .

Java [42] – Aplikacja uruchamiana w wierszu poleceń (CLI – command-line-interface) z przekazywanymi opcjami

Wiele programów, także bioinformatycznych, uruchamia się podając nazwę programu a także zestaw opcji, które sterują sposobem działania programu, wskazują plik wejściowy oraz wyjściowy itp. Podczas tej lekcji napiszemy tego typu aplikację, która będzie odczytywała plik zawierający sekwencje nukleotydów DNA a następnie znajdywała szukaną sekwencję, odwracała ją i zmieniała w sekwencję komplementarną.

Zasada działania aplikacji

Programy działające w wierszu poleceń, które dotychczas znalazły się w tym kursie, działały na dwa sposoby. Niektóre po prostu uruchamialiśmy i działały od początku do końca bez pobierania informacji od użytkownika (albo ewentualnie pobierały je z pliku), inne umożliwiały na interakcję z użytkownikiem, który wybierał opcje menu czy wpisywał dane.
Wiele programów uruchamianych w wierszu poleceń (ang. Command Line Interface – CLI) działa jednak w innym sposób. Polega on na tym, że przy uruchamiania programu użytkownik podaje szereg parametrów, które następnie są używane przez program. Parametry te mogą dotyczyć tego jak program ma działać, nazwy pliku wejściowego, pliku do którego mają być przekazane wyniki itp.

Na przykład:


clustalw -infile=sekwencje.fasta -outfile=sekwencje_wyrownane.fasta -output=FASTA

Wywołany zostaje program clustalw służący do dopasowywania sekwencji nukleotydów, który ma pobrać sekwencje z pliku sekwencje.fasta, a wynik sformatować w formacie FASTA i zapisać w pliku sekwencje_wyrownane.fasta

Dla początkującego może to się wydawać trudne i mało intuicyjne ale nie bez powodu tego typu programy są bardzo popularne w systemach Uniksowych, także w bioinformatyce. Do najważniejszych zalet takiej obsługi programów należą: szybkość uruchamiania i przekazania parametrów, łatwość dokumentowania wywołania programów wraz z konkretnymi zestawami parametrów, łatwość uruchamiania programów w skryptach co pozwala np. na automatyczne wielokrotne uruchomienie programu z różnymi zestawami parametrów.

Tym razem pokażę jak pisać tego programu w Javie. Napiszemy przy okazji program bioinformatyczny, który może się przydać przy pracy z sekwencjami nukleotydów zapisanymi w formacie FASTA.

Proste przekazanie opcji z linii komend

Zacznijmy od prostego programu, który będzie przyjmował parametry podczas jego uruchamiania.
Stwórz nowy projekt o nazwie „Parametry”.

Przyjrzyjmy się teraz klasie wygenerowanej automatycznie przez NetBeans:

Zauważ, że w pierwszym komentarzu znajduje się informacja, że args zawiera argumenty linii poleceń. Jest to tablica łańcuchów znaków, która jest parametrem metody main. Dotychczas nie używaliśmy jej, teraz to się zmieni.

Uzupełnij kodem metodę main:

Po uruchomieniu z poziomu NetBeans nic ciekawego nie uzyskamy, jedynie w okienku z wynikiem działania programu uzyskamy napis Parametry: – nie podaliśmy żadnych parametrów. Co prawda da się to zrobić z poziomu NetBeans ale czas uruchomić program z linii komend podając parametry. Najpierw jedna stwórzmy plik jar. Przypominam, że można to zrobić wybierając z menu Run->Clean and Build.
Otwórz teraz okno terminala. W Windows można je uruchomić wpisując cmd w okienku menu uruchamiania aplikacji, jeśli używasz innych systemów operacyjnych zapewne wiesz jak to zrobić ;-)
Teraz przejdź do podkatalogu dist, który znajduje się w katalogu z projektem.
Znajdują się tam pliki: Parametry.jar oraz README.TXT
Wykonaj polecenie:
(znak $ jest znakiem zachęty linii komend, w Twoim terminalu może wyglądać inaczej. Nie przepisuj go.)


$ java -jar parametry.jar

Efekt podobny do poprzedniego. Zatem przekażmy parametry do naszego programu:


$ java -jar parametry.jar par1 par2 par3
Parametry:
Parametr 1 = par1
Parametr 2 = par2
Parametr 3 = par3

Jak widać tym razem możemy wydrukować poszczególne parametry, które przekazaliśmy do programu przy jego uruchamianiu. A skoro tak, to możemy ich także użyć w dowolny inny sposób.

Uzupełnij kod o polecenia:


System.out.println("-----------------");
if (args[0].equalsIgnoreCase("o"))
System.out.println("Otwieram plik "+ args[1]);
else
System.out.println("Błędny parametr");

Trzeba ponownie zbudować plik jar (Run->Clean and Build).
W terminalu musisz wyjść z katalogu dist i ponownie do niego wejść:


$ cd ..
$ cd dist


Uwaga: W systemie Windows należy wyjść z katalogu dist przed zbudowaniem jar-a.

Oczywiście zamiast wchodzić i wychodzić z katalogu dist można uruchamiać program z katalogu powyżej katalogu dist:


$ java -jar dist/parametry.jar par1 par2 par3

będę się jednak trzymał poprzedniej konwencji.

Teraz znów uruchamiamy program:

Jak widać pierwszy parametr służy do sterowania przebiegiem programu, drugi zawiera nazwę pliku do otwarcia.
Taki sposób daje dość duże możliwości przekazywania parametrów ale ma pewną istotną wadę: jest bardzo sztywny. Trzeba zawsze przekazywać parametry w określonej kolejności. Bardziej użyteczny jest sposób pokazany powyżej na przykładzie programu clustalw polegający na tym, że parametry są odpowiednio oznaczane, mamy więc do czynienia z parami: nazwą parametru i jego wartością, przy czym kolejność tych par jest dowolna.
Można oczywiście samemu napisać kod, który po pobraniu parametrów rozpoznawałby nazwy parametrów i przypisane do nich wartości. Proponuję jednak użyć już istniejącej biblioteki, która znacznie ułatwia to zadanie.

Biblioteka Commons CLI

Wejdź na stronę: https://commons.apache.org/proper/commons-cli/
Znajduje się na niej krótki opis możliwości biblioteki.

Pobierz aktualną wersję biblioteki Commons CLI z działu „Download”, obecnie jest to plikcommons-cli–1.4-bin.ziplubcommons-cli–1.4-bin.tar.gz. Rozpakuj pobrany plik i umieść w wygodnym miejscu.

Następnie utwórz projekt o nazwie seqreverter.
Dołącz do projektu plik commons-cli-1.4.jar oraz dokumentację tej biblioteki znajdującą się w pliku commons-cli-1.4-javadoc.jar.
Instrukcja wyjaśniająca jak to zrobić znajduje się w lekcji „Java [27] – Pakiety, biblioteki`„.

Teraz umieść w metodzie main kod:

Zbuduj plik jar, przejdź do katalogu dist uruchom program bez parametrów:


$ java -jar seqreverter.jar
*** ERROR: ***
Missing required options: i, s
usage: java -jar seqreverter
-i,--input Plik wejściowy
-o,--output Plik wyjściowy
-s,--sequence Nazwa (lub jej część) sekwencji do odwrócenia

Jak widać program przerwał działanie i wyświetlił informację o tym jakich obowiązkowych opcji brakuje i wyświetlił krótką pomoc dotyczącą możliwych opcji.

Wywołajmy zatem program z obowiązkowymi opcjami:


$ java -jar seqreverter.jar -i dane.fasta -s Zea
Przekazane opcje:
Plik wejściowy: dane.fasta
Plik wyjściowy: null
Sekwencja: Zea

Program się uruchomił i wyświetlił wartości przekazanych opcji.
Teraz użyjmy wszystkich opcji:


$ java -jar seqreverter.jar -i dane.fasta -s Zea -o rezultat.fasta
Przekazane opcje:
Plik wejściowy: dane.fasta
Plik wyjściowy: rezultat.fasta
Sekwencja: Zea

Można też użyć długich nazw opcji, przy czym można mieszać nazwy krótkie i długie:


$ java -jar seqreverter.jar --input dane.fasta -s Zea --output rezultat.fasta
Przekazane opcje:
Plik wejściowy: dane.fasta
Plik wyjściowy: rezultat.fasta
Sekwencja: Zea

Teraz pozostaje „tylko” dodać sensowną funkcjonalność naszemu programowi.

Dodajemy funkcjonalność

Pliki FASTA to pliki tekstowe służące do przechowywania sekwencji DNA, RNA albo białek w dość prostym formacie. Może on wyglądać np. tak:

Magnolia_stellata
CTGCTAACTCTCAGTTTGGTCCTACTTCTGGTTCATTTTGTTACTAA
AAACGGAGGGGGAAACTCAGTACCAAATGCTTGGCAATCCTTGGTAG
AGCTTATTCATGATTTCGTGCCGAACCCGGTAAACGAACAAATAGGT
GGTCTTTCCGGAAATGTTCAACAAAAGTTTTCCCCTCGCATCT
Solanum_tuberosum
CTACTAACTCTCAGTTTGGTCCTACTTTTGGTTTATTTTGTTACTAA
AAAGGGAGGAGGAAACTCAGTACCAAATGCTTGGCAATCCTTGGTAG
AGCTTATTTATGATTTCGTGCTGAACCCGGTAAACGAACAAATAGGT
GGTCTTTCCGGAAATGTTAAACAAAAGTTTTCCCCTCGCATCT
Mimulus_guttatus
AGATGCAAGGGAAAAACTTTTGTTTCACATTTCCGGAAAGACCACCT
ATTTGTTCGTTTACCAGGTTCGGCACGAAATCATAAATAAGCTCTAC
CAAGGATTGCCAAGCATTTGGTACTGAGTTTCCTCCTCCCTTTTTAG
TAACAAAATGAACAAAAAGTAGGACCAAACTGAGAGTGAGTAG
Orobanche_coerulescens
CTGCTAACTCTCAGTTTGGTCCTACTTCTGATTCATTTTGTTACTAA
AAAGGGAGGAGGAAACTCAGTACCAAATGCTTGGCAATCCGTGGTAG
AGTTTATTTATGATTTCGTGCTGAACCTGGTAAACGAACAAATAGGG
GGTCTTTCCGGAAATGTTAAACAAAAGTTTTTCCCTTGCATCT
Orobanche_eliator
CTACTCACTCTCAGTTTGGTCCTACTTTTTGTTCATTTTGTTACGAA
AAAGGGAGGAGGAAAGTCAGTACCAAATGCTTTTCAATCCGTGTTAG
AGCTTATTTATGATTTTGTGCCGAACCTGGTAAACGAACAAATAGGT
GGTCTTTCCGGAAATGTGAAACAAAAGTTTTTCCCTTGCATCT

Jak widać linie zaczynające się od znaku > zawierają opis sekwencji, np. nazwę gatunku, kolejne linie zawierają sekwencję nukleotydów (lub aminokwasów), aż kolejnej do linii ze znakiem >. Sekwencja nukleotydów może być podzielona na wiele linii, ale może też zawierać się w jednej.

Program seqreverter będzie odczytywał plik w formacie FASTA a następnie dokonywał zmiany sekwencji, której opis będzie zawierał przekazany do programu łańcuch znaków w ten sposób, że najpierw odwróci sekwencję a następnie utworzy na jej podstawie sekwencję komplementarną. Tego typu czynność często wykonuje się przy pracy z sekwencjami nukleotydów. Zauważ, że sekwencja gatunku Mimulus guttatus różni się znacznie od pozostałych, jest wobec nich odwrócona i (częściowo) komplementarna.
Nasz program będzie miał nieco ograniczoną funkcjonalność – nie uwzględnia pozostałych symboli kodu IUPAC i działa wyłącznie na sekwencjach DNA (nie uwzględnia „U”).

Utwórz plik o nazwie dane.fasta, umieść w nim powyższe sekwencje i zapisz w katalogu z projektem (powyżej katalogu dist).

Teraz utwóż drugą klasę w naszym projekcie i nazwij ją Sekwencja.
Zawartość pliku Sekwencja.java

Jak widać jest to prosta klasa, zawierająca dwa pola odpowiadające opisowi sekwencji i samej sekwencji nukleotydów a także odpowiednie akcesory i modyfikatory.

Teraz do klasy głownej dodaj kilka metod a także uzupełnij metodę main. Kompletny kod pliku Seqreverter.java powinien wyglądać tak:

Wyjaśnienia zasady działania znajdują się w komentarzach.

Teraz utwóż plik jar, przejdź do katalogu dist i wykonaj polecenie:


$ java -jar seqreverter.jar -i ../dane.fasta -s Mimulus -o ../rezultat.fasta

Powyżej katalogu dist znajdziesz plik rezultat.fasta.
Otwóż go w edytorze tekstu i porównaj z plikiem dane.fasta. Teraz sekwencja Mimulus guttaus pasuje do pozostałych.
Zauważ, że sekwencje nukleotydów zawarte są teraz w jednej linii. Ponadto sekwencja Mimulus_guttatus jest odwrócona.
Jeśli nie podasz pliku wejściowego to zmieniony zostanie plik wejściowy. Jeśli zatem chcesz zmienić wiele sekwencji, których wyszukanie wymaga podania różnych łańcuchów znaków to dobrym pomysłem jest najpierw skopiowanie plikufasta a następnie dokonywanie kolejnych modyfikacji na kopii.

Leave a Reply