제 10 장기초 Perl 프로그램밍 10.1 Perl? Perl 언어는 C 언어와는달리컴파일러가필요하지않은인터프리트 (Interpret) 언어이다. 이는 90년대컴퓨터교육의광풍이불었을때많이가르치던 GW-BASIC 과같이프로그램을입력하면바로실행이되는형태를띈다. Perl 의또다른장점은운영체제 (Operating System) 에독립적이라는점이다. 즉, 윈도우즈에서실행한 Perl 프로그램은특별한예외 ( 시스템관련된코드는운영체제의특성에영향을받는다 ) 를제외하고는바로 UNIX 에서실행이가능하다 ( 그림 10.1). 그림 10.1 같은프로그램 (prog1.pl) 을 Linux 와윈도우에서실행한화면 Perl 언어의문법은 C와비슷하면서도변수를선언할때변수의타입 ( 예, 숫자, 문자열등 ) 을설정하지않고바로사용이가능하기때문에초보자로쉽게프로그래밍을할수있다. 이에반해서 C 프로그램의경우는변수를사용하기전에해당형식을설정해야하고, 설정이되고나면변경하는것이불가능하다. 또한다른형태의변수간데이터이동을위해서형변환에대한고려를해야하는어려움이있다. 마지막으로, C 프로그램을배울때가장많은사람이포기하는부분이포인터 (pointer) 인데, 포인터를이해하지못하면 C 프로그램을효율적으로만들수없는, 가장어려운관문이된다 ( 그림 10.2). 이에반해서 Perl 은포인터없이도다양한문자열처리가가능하도록설계가되었다. 이와같은장점이많은사람들로하여금 Perl 을사용하고, 생물정보학에서도초기에는 Perl 프로그램을많이사용하였다. 그림 10.2 C 의포인터개념. 포인터는메모리의주소이다. Perl 코드는사람에따라서일반적인프로그램처럼짤수도있지만, 간결하게코드를짤수있는것으로도유명하다. 원래프로그램언어를개발할때간결하게프로그래밍을할수있도록설계를하였고, 같은프로그램도다양한형태로표현될수있도록고려를하였다. 가장극단적인예로는 Perl 로시를쓰는경우도있는데, 아래그림이그예이다 ( 그림 10.3).
그림 10.3 Perl 로쓰여진시예제 (http://www.perlmonks.org/?node_id=1111395) 마지막으로 Perl 의강점은문자열처리에활용하는정규표현식 (Regular Expression) 이다. 텍스트파일을읽어서패턴분석을하는데에는정규표현식을이용해서매우간단하게프로그램을만들수있을뿐아니라, 매우빠르게그처리를진행할수있다. 그런데이표현식은익숙해지지않으면해독이안되는암호화된문자열처럼보인다 ( 그림 10.4). 생물정보학에서도이부분때문에여러연구자, 개발자들이 Perl 을애용하고있다. 그림 10.4. Perl 정규표현식의예제
Box 10.1. Regular expression ( 정규표현식 ) 그림 10.4 에서보이는것처럼엄청나게복잡한암호처럼보이는문자열을정규표현식 (Regular Expression) 이라고한다. Perl 의가장큰강점은, 복잡한문자열패턴을단한줄의정규표현식으로정리를할수있다는점이다. 또한이정규표현식의실행속도는 C로복잡하게프로그램을짠것과대등한속도를낸다. 이때문에텍스트자료처리등에 Perl 의정규표현식이자주사용되곤하였다. 생물정보학 (Bioinformatics) 의경우는전형적으로 text 파일을많이다루는분야이다. 계속적으로소개가되지만, 대부분의결과물은텍스트형태로저장이되며 ( 일부용량때문에압축하는경우제외 ), 이결과에서원하는정보를추출할일을자주수행하게된다. 왜냐하면대부분의생물정보학분석은한번에끝나는것이아니고수십단계를거쳐서진행이되기때문에, 결과로부터원하는정보를빠르게추출해서다음단계에서분석하는작업을거치게된다. 10.2 Perl 프로그램시작하기 Perl 프로그램을만들기위해서는 Perl 인터프리터 (Interpreter) 가있어야한다. 대부분의 UNIX/Linux 서버에는 Perl 인터프리터가기본적으로설치되어있다. 윈도우에서 Perl 프로그램을수행하기위해서는 ActivePerl (http://www.activeperl.com/) 에서 Perl 인터프리터를다운받아서설치하면된다 ( 그림 10.5). Perl 인터프리터가있는지확인하기위해서 UNIX/Linux 에서는 perl v를입력해서 Perl 버전이나오면설치가되어있는것이다. 윈도우즈역시명령프롬프트 (cmd) 에서같은명령을입력하면확인가능하다 ( 그림 10.6, 10.7).
그림 10.5 http://www.activeperl.com 웹사이트. 무료로 Perl interpreter 를다운로드받을수있다. 그림 10.6. UNIX/Linux 서버에서 Perl 인터프리터를확인한화면.
그림 10.7. 윈도우즈에서 Perl 인터프리터를실행한화면. 10.3 Hello, Perl! 어떤언어든제일먼저프로그래밍연습하는것이바로이 Hello 시리즈이다. 지금 Perl 에대해서공부를하고있으므로, Hello, Perl! 을출력하는프로그램을작성해보도록한다. 6장에서소개한 vi 에티터를사용해서아래화면과같이프로그램을입력한다 ( 그림 10.8). 그림 10.8. Hello, Perl 프로그램코드. Perl 프로그램작성시가장첫줄은 #!/usr/bin/perl w을넣는다. 가장앞에 # 은주석이라는의미이나,! 과함께사용하면 UNIX/Linux 에서해당프로그램구동시 /usr/bin/perl 프로그램을인터프리터로서쓰라는것을의미한다. -w 는경고 (warning) 을출력하는옵션인데, 초기에프로그래밍을할때유용하게사용할수있다. 특히, 변수 (variable) 의오탈자로인해서오동작하는경우를쉽게찾아낼수있다.
Box 10.2. /usr/bin Linux 의대부분명령어는모두프로그램으로되어있다. 6장에서소개한모든명령어는다프로그램인데, 이들은전부 /usr/bin 폴더에위치해있다. Perl 프로그램을할때상단에 #!/usr/bin/perl w로명시하는것도 perl 프로그램이 /usr/bin 에존재하기때문이다. ls 명령어로해당파일들이존재하는지확인해보도록하자. 다음줄에는 use strict; 을명시하였는데, 이는변수를정의하지않고사용하는경우는에러를내고프로그램을중지하도록하는기능을한다. 이기능이있는이유는, Perl 에서는기본적으로변수를선언하지않고사용하는것이가능하다. 프로그래밍중간에오탈자로인해서변수이름이달라졌는데, 프로그램작성자가이를눈치채지못하고넘어가게되면프로그램이원하는대로동작하지않게된다 (Box 10.3 참조 ). 따라서, 이를방지하기위하여변수를반드시선언하고사용하는기능을 use strict 에서제공을해준다. Box 10.3. Perl 에서오탈자로인해서원하는결과를얻지못하는경우 아직 perl 프로그램은 1 개만보았지만, 선행학습겸변수사용에대해서간략하게소개를한다. $a와 $b 변수를사용해서합산을하는프로그램의예제이다. 프로그램구동결과 4가나오는것을확인할수있다 (1+3=4). 여기서프로그램을짤때오탈자가생겨서 $a 가 $s 가된다면 ( 아래참조 ), 결과가 0+3=3 으로계산이된다. 이때, use strict; 을사용하고 $a 와 $b 를정의해서 ( 변수정의는 my 를사용한다.) 가면다음와같은에러가출력된다.
위에서보는것처럼 $s 변수가선언되지않았는데, 5번째줄에서사용되어서에러를출력하고프로그램을종료하게된다. 이렇게되면중간에프로그램작성자가문제가있었음을확인하고수정해서원하는프로그램을작성할수있게된다. 마지막으로화면에출력하는줄인 print Hello, Perl!\n ; 을입력한다. print 는화면에문자열을출력하는함수이며, 가장마지막의 \n은개행문자로줄바꿈을의미한다. 만들어진프로그램 (prog1.pl) 을 Linux 서버상에서실행해보도록한다. 프로그램실행방법은프롬프트에서 perl prog1.pl 을입력하면된다. 현재위치에 prog1.pl 이있어야만 Perl 인터프리터가이를읽어서프로그램을구동하게된다 ( 그림 10.9). 그림 10.9. prog1.pl 프로그램을구동한화면. 원하는대로 Hello, Perl! 이출력되었다. 보는바와같이 Hello, Perl 프로그램이완성되었다. 10.4 숫자합산프로그램 다음으로좀더복잡한프로그램을작성해보도록한다. 1부터 100 까지의합을구하는프로그램을작성하는데, 프로그램은 1부터 100 까지숫자를증가시키면서그합을저장하고, 100 에도달하면해당값을출력하도록프로그래밍한다. 이프로그램을위해서 Perl 의변수에대해서소개를한다. 프로그램에서변수 (variable) 란, 변하는값을저장하는공간을의미한다. 실제로는메모리상에서특정공간을할당받고, 여기에값을저장하게된다. Perl 에서변수를사용하기위해서는 my 명령어를통해서변수를정의하게된다 ( 그림 10.10).
그림 10.10. Perl 변수 (Variable) 의예제프로그램. 위의프로그램을보면변수 a는 $a로표기되고 my 에의해서정의되었다. 그리고초깃값을 1로가진다. $b 는초깃값으로 2의값을가지게된다. $c는 0의값을가진다. 이렇게정의된변수는프로그램안에서다양한값을가질수있는데, 위의예제에서는변수 c에 a와 b의값을합산한값 ($a + $b) 를할당하도록하였다. 이과정을거치면변수 c에는 1+2=3 의값이저장되게된다. 그림 10.11. 예제프로그램 (prog2.pl) 실행결과. 프로그램을실행하면예상대로 c = 3 이출력된다 ( 그림 10.11). 다음으로 Perl 의루프 (loop) 문에대해서간략하게알아보도록한다. Perl 에서는 C와동일한여러가지루프문을제공하는데, 여기에서는 for 문에대해서알아보도록한다. 그림 10.12. for loop 예제프로그램. 위의예제프로그램을보면 for 문안에서변수 i가정의되고 0의값을가진후 (my $i = 0), i값이 10보다작을때까지 ($i<10) 반복을한다. 한번반복할때마다 i의값은 1씩증가 ($i++) 한다. for 문에의한반복은이와같이, 초기값 (0), 종료조건 ($i<10), 한번반복할때마다실행하는명령어 ($i++) 로구성되어있고, { 와 } 로감싸져있는줄 (print Hello, Perl!\n ;) 을반복하게된다 ( 그림 10.12). 이프로그램을구동하게되면 i값이 0부터 9까지 (10 일때는 $i<10 조건에맞지않아서루프가종료된다.) 변하면서루프안의명령어를실행한다.
그림 10.13. for 문 Perl 프로그램실행결과. 프로그램구동결과위의화면처럼 10 줄의 Hello, Perl! 이실행됨을알수있다. 마지막으로 1부터 100 까지의합을구하는프로그램을 for 문을활용해서구현해보도록한다. 바로위의예제에서 10번반복하는프로그램코드를 100 번반복하도록수정한후에, 첫예제에서사용한명령 ($c = $a + $b;) 을활용해서숫자를계속합산하도록코드를작성한다. 단, i값이 1부터 100 의값을가지도록조정을해야한다 ( 그림 10.14). 그림 10.14. 1 부터 100 까지의합을구하는프로그램. 위의프로그램을보면 for 문을활용하고 i 변수가 1부터 100 까지의값을가지면서 1씩증가하도록설정하였다. 그리고 tot 변수를정의하여, i 의값을 tot 에계속합산 ($tot = $tot + $i) 하도록하였다. 이렇게하면프로그램이 100 번의반복을통해서 1부터 100 까지의합을계산할수있게된다. 실행결과는다음과같다 ( 그림 10.15). 그림 10.15. 1 부터 100 까지합을계산하는프로그램실행결과. 10.5 파일입출력프로그램 이제 Perl 을이용해서파일을열고닫는프로그램을작성해보도록한다. 실제로생물정보학에서사용하는많은데이터들은텍스트파일로되어있다. 따라서 Perl 로파일을열고내용을읽어내는것은매우유용하게사용될수있다. Perl 에서파일을여는함수는 open 이며, 닫는함수는 close 이다. 파일을열게되면파일핸들 (file handle) 이생성이되는데, 이를이용해서파일내용을읽거나쓸수있게된다. 먼저파일을열고내용을읽는예제프로그램을확인해본다 ( 그림 10.16).
그림 10.16. 파일을여는프로그램예제. 위의예제에서보면 open 명령어다음괄호를열고 2개의인자가사용되었다. 하나는대문자로 DATA 이고, 다른하나는파일이름이다. open 명령어의첫번째인자가파일핸들이고, 이는처음에소개된 STDIN, STDOUT, STDERR와같은종류의것이된다. 단 DATA는프로그래머에의해서생성되고소멸될수있다. 실제 prog4.pl 파일이존재하면에러없이 open 명령어가실행될것이다. 다음에있는 while 명령은 for 문과비슷한루프명령어인데, while 다음의조건이충족하면 { } 안의명령을실행하게된다. 본프로그램에서의 while 문의조건은 my $line = <DATA> 인데, $line 변수를정의하고 DATA라는파일핸들에서한줄을읽어오는명령에해당된다. 이때명령어전체는파일에서한줄을정상적으로읽어오면참 (true) 을반환하고, 그렇지않고에러가발생하거나파일의끝 (End of File) 에도달하게되면거짓 (false) 을반환하게된다. 이에파일의끝까지모두읽고난다음에는 my $line=<data> 가자연스럽게거짓 (false) 이되어서 while 루프를종료하게된다. 결국이 while 명령어는파일을열고난다음처음부터끝까지한줄씩데이터를가져오는역할을담당하게된다. while 문안에서는 line 변수의값을출력하도록되어있으므로, 파일을연후, 처음부터한줄씩읽어서화면에출력하는과정을거치게된다. 프로그램실행결과는아래와같다 ( 그림 10.17). 그림 10.17 프로그램실행결과 prog4.pl 파일의모든내용이출력되었다. 기존에배운 cat 명령으로내용이같은지확인해본다 ( 그림 10.18).
그림 10.18. cat 프로그램으로 prog4.pl 파일내용을확인한결과. 내용이동일함을확인할수있다. 이프로그램을기반으로해서특정파일의줄수를세는프로그램을작성해볼수있다. 위의프로그램에서, 파일내용을출력하는것대신루프가한번씩돌때마다숫자를 1씩증가시키는코드를넣으면특정파일의줄수를확인할수있게된다. 프로그램은아래와같다 ( 그림 10.19). 그림 10.19. 파일의줄수를세는프로그램. 이전프로그램과다른점은 cnt 변수가정의되고, 루프를돌때마다 1씩증가시키는코드 ($cnt++) 가들어가있다. 이는루프를몇번도는지를셀수있고, 이는곧파일이줄수와동일하게된다. 프로그램실행결과, prog4.pl 파일은총 11줄을가지고있음을확인할수있다 ( 그림 10.20). 그림 10.20. prog4.pl 파일의줄수를세는프로그램구동결과. 10.6 배열 배열 (array) 에대한내용을살펴보도록한다. 배열이라함은변수의집합체를의미한다. 프로그램작성시 26개의변수가필요한경우, $a부터 $z까지 26개의변수를정의할수도있지만, 좀더쉽게 @a ( 배열 a) 를선언하고이안에 0번부터 25번방을만들어서데이터를저장하는것도가능하다. 예를들어서, 1, 2, 3, 5, 8의수열을만들어보는프로그램을짜보도록한다. 1 과 2는초기값으로, 3은 1+2 로계산이되고 5는 2+3, 즉 1, 2, 3에서가장마지막의두개의수를합산하고, 8은 3 + 5 로, 앞과동일한방법으로계산하게되면원하는수열을얻을수있다. 이를직관적으로프로그램을작성하게되면아래
그림 10.21 과같이 5 개의변수를사용해서구현할수있다. 그림 10.21 1,2,3,5,8 수열을생성하는프로그램 이프로그램의실행결과는아래와같다 ( 그림 10.22). 그림 10.22 프로그램실행결과. 이프로그램을배열을이용해서프로그램을작성할수있다 ( 그림 10.23). 그림 10.23 배열을이용한프로그램.
위의코드에서배열변수 @a 의선언은 my 로진행한다. 이후에배열에데이터를할당하기위해서 $a[0], $a[1] 과같이위치정보 (0, 1) 을표시하고값을할당하면된다. 그다음코드는 3번째값은 1번째와 2번째변수의합으로표현되고, 4번째, 5번째의경우도각각자신의앞과두번째앞에있는값의합으로정의가된다. 따라서 for 문을이용해서 $i의값을 2부터 4까지순환하면서 $a[$i] = $a[$i-1] + $a[$i-2]; 명령을수행하여원하는값을배열 @a 의 $i번째방에할당을한다. 마지막으로계산이끝나고출력을할때도 for 문을이용해서결과를출력한다. 마지막 for 문의두번째조건에해당하는부분이 $i<@a 로되어있는데, $i는변수이고 @a 는배열이다. 그런데이코드가에러가나지않고동작하는것은배열변수가일반변수 (Scalar) 와비교나변수에할당되게되는경우에는해당배열이가지고있는요소 (element) 수를반환하는기능을자동으로수행한다. 따라서 $i<@a 는이프로그램에서 $i<5 와동일한효과를지닌다. 그림 10.24 프로그램구동결과 이와같이배열을사용하게될경우, 프로그램이좀더체계적으로구성이될수있다. 10.7 외부에서인자전달받기 외부에서인자를전달받는것은, ls 나 grep 명령어가뒤에인자를입력해서원하는기능을수행하게하는것과동일하다. Linux 에서는프로그램구동시에인자를받을수가있는데, perl 에서는 @ARGV 라고하는특수변수에해당내용이저장이되게된다. 따라서, 원하는외부인자를접근하기위해서는 @ARGV 배열변수를사용하면된다. 예를들어서사용자가 prog9.pl 을구동시킬때 1000 이라는값을같이입력하면, 1000 값을출력하는프로그램을작성해보도록한다 ( 그림 10.25). 그림 10.25 첫번째외부인자출력하기 프로그램구동은아래와같이진행한다. 1000 값을 prog9.pl 다음에같이입력을하면, 그림 10.26 과같은결과를얻게된다.
그림 10.26 prog9.pl 의구동결과 ARGV 변수를이용해서 1부터 100 까지합을계산하는프로그램을개선해서, 1부터입력받은값까지의합을계산하는프로그램을구성해보도록한다. 그림 10.27 인자를받아서, 1 부터인자까지의합을구하는프로그램 외부인자를받아서구동하는프로그램이기때문에다양한결과를프로그램을고치지않고얻을수있다 ( 그림 10.28). 그림 10.28 프로그램실행결과 외부환경인자를받아들일수있게되면, 보다효율적인프로그램및상황에맞는결과를얻어낼수있다.