티스토리 뷰

리눅스 커맨드라인 (Command-line)에서 for문을 사용해서 반복 실행이 가능하다!!! 이걸 처음 알았을 때 내게 정말 대박! 이었다. 만약 커맨드라인 (Command-line), 터미널(Terminal), 배쉬(Bash)가 무엇인지 궁금하다면 여기를 클릭! 커맨드 라인을 사용해 프로그램을 돌려본 사람이라면 프로그램을 여러번 반복해서 돌려야 하는 일이 힘들다는 것을 알것이다. 바이오인포매틱스를 하면서 이런 어려움이 피부로 느껴진다. 예를들어 샘플이 60개 라고 하면 파일이 60개가 나오는데, 분석을 하려면 프로그램을 적게는 몇개에서 많게는 열개 넘게 돌려야 한다. 만약 10개의 프로그램을 돌려야 분석이 마쳐진다고 하면 60 X 10 총 600번의 커맨드 입력을 해야한다!!! 이 과정을 자동화 혹은 오토매이션 (automation)하는 방법이 여러가지가 있지만 가장 간단하면서 파워풀하게 사용할 수 있는게 for 문을 커맨드라인에 직접 사용하는 것이다. 여담으로 어떤사람이 워크숖에서 이걸 가르쳐줬더니 어떤 여학생이 울면서 자신이 몇일 밤을 새워가며 프로그램을 돌리던 이야기를 해줬다고 한다. 자, 본론으로 들어가서..


만약 여러분의 폴더에 sample01.txt sample02.txt sample03.txt 라고 하는 세개의 파일이 있다고 하자. 이 파일을 programX 를 이용해 분석해야 한다. programX는 커맨드라인에서 


$ programX sample01.txt 


와 같은 방법으로 실행할 수 있다. 그러면 프로그램을 세번 돌리는 것으로 모든 파일의 분석을 마칠 수 있다. 하지만 샘플이 60개라고 한다면 명령어를 60번 입력하는 것이 만만치 않다는 것을 느끼게 될 것이다. 이때 아래와 같이 명령어 입력을 한줄로 끝낼 수 있다.


$ for file in sample*.txt ; do programX $file;done


만약 코딩을 해본 사람이라면 쉽게 이해할 수 있는 for문이다. 혹시 for 문이 무엇인지 모르는 사람을 위해 설명하자면, 위 명령어는 총 세줄로 이루어져 있다. (for ~ 어쪄구, do ~ 저쩌구, done) 중간에 세미콜론(;)은 줄을 나누어 주는 표시이다. 첫줄는 for 변수이름 in 파일이름 으로 이루어져 있다. 파일 이름에는 와일드카드 (*)를 사용해 특정 문자열을 가진 모든 파일을 읽게 되어 있다. 다시말해 앞에 sample로 시작해 txt로 끝나는 모든 파일 (여기서는  sample01.txt sample02.txt sample03.txt 세개)을 읽어 하나씩 변수이름에 적용해 준다. 위에 file이라고 된 부분은 변수 이름으로 어떤 이름을 사용해도 상관 없다. 예를들어 for x in sample*.txt ; do programX $x;done 와 같이 사용해도 무방하다. 다만 변수이름은 x 와 같이 너무 제너널한것 보다는 file과 같이 이게 무엇인지 예상할 수 있는 이름을 사용하는 것이 좋다. 여튼 이렇게 첫줄에서 각 파일을 file이라는 변수에 한개씩 적용한다. 두번째줄인 do programX $file 부분이 실제로 프로그램을 수행하는 부분이다. 'do'라는 형식을 사용해 '이 줄에 있는 것을 실행할꺼다'라고 알려준다. programX $file부분이 실제 프로그램이 동작하는 부분이다. $file은 위에서 지정한 변수이름 file을 가리킨다. 그냥 file이라고 적으면 이게 프로그램 이름인지, 파일 이름인지, 변수 이름인지 알 수 없으므로 위에서 지정한 변수이름이라는 것을 확실히 말해주기 위해 $를 앞에 붙인다. 위에서 file에 각 샘플을 적용 했으므로 첫번째 실행시 programX sample01.txt 가 되고, 두번째 실행시 programX sample02.txt가 될 것이다. 마지막으로 programX sample03.txt 까지 돌면 for 문이 끝나게 된다. 마지막 'done'부분은 for 문이 끝난다는 것을 말해준다. 형식이라고 생각하면 되겠다. 


고급과정

여기까지 문제없이 따라왔다면, 또 for문의 파워풀함을 느꼈다면 for문을 실제로 많이 사용해 보자. 역시 모든지 실제로 사용해야 내게 덕이 되는 법이다. 그런데 쓰다보면 어느순간 막히는 때가 생긴다. 예를 들면, 입력해야 하는 파일이 두개인겨우, 또는 입력하는 파일과 출력하는 파일 이름을 따로 지정해 주어야 하는 경우 말이다. 그럴때는 아래와 같이 사용할 수 있다. 아래 예제는 내가 실제로 사용하는 구문이다. 예를들어 시퀀싱 파일이 sample01_R1.fastq.gz, sample01_R2.fastq.gz, sample02_R1.fastq.gz, sample02_R2.fastq.gz 의 네개 파일이 있다고 하자. 그리고 bowtie2라는 프로그램을 돌린다고 하자. 프로그램을 한번씩 돌리면 아래와 같이 할 수 있다.


$ bowtie2 -x reference -1 sample01_R1.fastq.gz -2 sample01_R2.fastq.gz -S sample01.sam 2> sample01.out


자세히 보면, 샘플 파일 두개를 읽어 결과 파일 sample01.sam 파일을 만들고, 마지막에 통계값이 나오는 부분을 standard error를 저장해주는 2> 를 이용해 sample.out으로 저장해 준 것이다. 이과정이 어려운 이유는 for 문에서 *.fastq.gz로 파일을 부르면 4개의 파일이 각각 불러질테고, *R1.fastq.gz로 부르면 R2값을 부를 수 없게되기 때문이다. 이럴때는 ${x%_R1}을 이용해 해결 할 수 있다. 


$ for x in *R1.fastq.gz; do bowtie2 -x reference -1 $x -2 ${x%_R1*}_R2.fastq.gz -S ${x%_R1*}.sam 2> ${x%_R1*}.out ; done


이렇게 하면 프로그램이 두번 돌면서 R1부분을 R2로 혹은 .sam, .out으로 치환해 적용하게 된다. 


차례

1. 터미널 설치하기

2. 기본 명령어 익히기 




도움이 되셨다면

공감 눌러주세요 ^.^ 

신고
댓글
댓글쓰기 폼
공지사항
Total
8,556
Today
1
Yesterday
74
링크
«   2017/10   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
글 보관함