Perl 문법설명

2015.06.19 17:07

졸리운_곰 조회 수:388

 

 

출처 : http://ttongfly.net/zbxe/?document_srl=45342&mid=scriptprogramming&listStyle=&cpage=

 

Perl 문법설명

 

 

다음의 기사는 월간 프로그램 세계 1997년 6월호 특집기사로 실렸던 것입니다. 특집기사는 총 3부로 이루어져 있는데, 1부는 Perl의 소개, 2부는 Perl의 문법, 3부는 Perl을 이용한 CGI 예제 프로그램 작성으로 구성되어 있습니다. 제가 맡은 부분은 2부였고 총 분량의 절반에 해당합니다. 1부와 3부는 김대신(웹데이타뱅크)씨가 맡으셨습니다. 다음의 글은 제가 초안으로 작성한 텍스트 파일을 HTML문서로 약간 손을 본 것입니다.

차례

 

  1. 소개

  2. Perl의 문법
    1. 변수(Variable)
      1.   
      2. 수치(number)
          
      3. 문자열(string)
          
      4. scalar variable
          
      5. vector variable
          
      6. 특수한 변수(Special variable)
          
      7. 레퍼런스(reference)
          
      8. 배열의 배열, 해시의 배열, 배열의 해시
    2. 식(Expression)
      1.   
      2. 기본 연산자
          
      3. 추가 연산자
          
      4. 기본 입출력 연산자
          
      5. 비교 연산자
    3. Control Structure(제어 구조)
      1.   
      2. if
          
      3. unless
          
      4. while/until
          
      5. for
          
      6. foreach
          
      7. do/while, do/until
          
      8. goto
          
      9. next, last, redo
    4. 서브루틴(Subroutine)
      1.   
      2. 정의와 사용
          
      3. my와 local
    5. 패턴 매칭(Pattern Matching)
      1.   
      2. 정규 표현식(regular expression)
          
      3. match, substitute, translate
          
      4. 문자열 pattern 조작

소개

펄은 임의의 텍스트 파일들을 검색하고 그 파일에서 정보를 추출하며, 그 정보에 따라 보고서를 작성하는데 최적화된 언어이다. 또한 많은 시스템 관리 작업에 좋은 언어이다. 이 언어는 실용적일 수 있도록 만들어졌기 때문에 크기가 아주 작거나 아름답게 만들어지지지 는 않았지만 사용하기 쉽고 효율적이며 완벽하다고 말할 수 있다. 펄은 C와 sed와 awk와 sh 등의 사람들이 친숙하게 생각하는 언어들의 장점을 모아서 만든 것이기 때문에 배우기 어렵지 않다. 표현식은 거의 C와 비슷하며, 다른 유닉스 유틸리티와는 달리 용량 등의 제한이 없다. 주로 text를 처리하는데 뛰어난 능력을 보여주지만, 바이너리 자료를 다루는데 있어서도 데이터베이스를 만드는 기능이 있을 정도이다. sed나 awk를 사용하는데 문제가 발생한다면 C로 짜는 대신에 펄로 작성하면 스크립트를 거의 바꾸지 않아도 된다.

2부. 펄의 문법

Perl의 저자, Larry Wall이 말했던 것처럼 Perl은 한 가지 일을 하기 위해 10가지 방법을 제시하는 언어이다. 어떻게(how) 할 것인지가 중요한 게 아니라 무엇을(what) 할 것인지를 먼저 생각하고 프로그래밍을 해야 할 것이다. 그러나 다양한 표현 방식들을 많이 익히면 익힐수록 프로그래머에게 더 많은 가능성이 열리는 셈이다. 다음의 글은 독자들이 기본적인 C프로그래밍을 이해할 수 있고 유닉스의 shell기반의 작업들에 무지하지 않음을 가정하고 쓰여진 것이다. 그러나 가능하면 초보자들도 이해할 수 있도록 쉬운 표현과 예제를 이용하였다. 다음의 설명은 Perl 5를 기준으로 쓰여졌으나, Perl 4에서도 무난하게 사용 가능할 것이다.


1. 변수(Variable)

기본적으로 Perl은 변수에 대해, C와 같이 강력한 type checking을 하지 않는다. 다시 말해서 '값이 어떤 방식으로 저장되어있는가'는 '어떻게 사용할 것인가'와는 별개의 문제라는 것이다. C프로그래밍에 익숙한 사용자라면 int c = 'x'; 으로 정의된 변수 c가 문자형으로도 정수형으로도 사용 가능한 것을 떠올릴 수 있을 것이다. 그런 것을 확장해서 생각해보면 Perl의 변수들은 여러 형태로 사용할 수 있다. 그것은 Perl 인터프리터(interpreter;해석기)가 내부적으로 자동 변환해 주기 때문에 가능한 것이다.

  1) 수치(number)

Perl에는 정수형 수치는 존재하지 않는다. 모든 수치는 double-precision floating point형 수치로 존재한다. 다음과 같은 형태의 수치는 float literal(소수형 상수)이다.


 

111.25
23.25e91
-12.5e29
-12e-34
3.2E-23


다음과 같은 형태의 수치는 integer-literal(정수형 상수)이다. 숫자 앞에 0이나 0x를 붙여쓰게 되면 각각 8진수와 16진수를 의미하게 된다.

 

342
-2423
0377
-0xf0


  2) 문자열(string)

문자열은 이름이 뜻하듯이 연속된 문자들의 순열이다. 일반적인 ASCII 문자는 128개로 표현이 되지만, Perl에서는 특수문자가 표현되어야 하기 때문에 extended ASCII를 지원하여 문자열 내부의 각각의 글자는 0에서 255까지의 ASCII값을 가지게 된다. 문자열은 여러 형태의 두 quotation mark로 감싸서 표현할 수 있는데, 대표적인 케이스는 ''(single-quote)와 ""(double-quote), ``(back-quote)이다. single-quote사이에 들어가는 문자열은 interpolation을 하지 않고, double-quote사이에 들어가는 문자열은 interpolation을 하게 되는 차이점이 있다. 그러면 interpolation이란 무엇인가 예를 보면서 이해하도록 하자.

 

$str1 = 'hellonneveryone';
$str2 = "hellonneveryone";
print $str1 . "n";
print $str2 . "n";


두 문장은 quotation mark가 다르다는 점을 제외하고는 차이점이 없다. 그런데 출력결과는 다음과 같이 다르게 된다.
 

hellonneveryone  # 이것은 str1의 출력 결과이다.
                   
hello              # 이것은 str2의 출력 결과이다.

everyone


위와 같은 escape character뿐만 아니라 이미 정의되어진 변수들을 문자열 안에서 사용하는 경우에도 interpolation의 가능 여부에 따라 그 변수가 해석되기도 하고 그렇지 않기도 한다.
 

$str0 = "I'm a boy.";
$str1 = 'hello $str0';
$str2 = "hello $str0";
print $str1 . "n";
print $str2 . "n";


결과는 다음과 같다.
 

hello $str0       # str1의 출력 결과
hello I'm a boy.  # str2의 출력 결과


single-quote 문자열에서 single-quote(')를 표현하는 방법은 backslash뒤에 single-quote를 쓰는 것이다.
 

print 'I'm a boy.';  # 출력 결과 I'm a boy.


다음은 double-quote안에서 특별한 효과를 가지는 escape character의 종류와 그 의미에 관한 표이다.
 

n newline 다음 줄로
r return 줄의 맨 앞으로
t tab 탭
f formfeed
b backspace
v vertical tab
a alarm bell
e ESC
73 octal value 8진수(여기서는 73(8) = 7*8+3(10) = 59(10))
x7f hexadecimal value 16진수(여기서는 7f(16) = 7*16+15(10) = 127(10))
cC 제어문자 C
  backslash
" double-quote
l 다음 글자를 대문자로
L 다음 글자를 소문자로
u 뒤에 오는 모든 글자를 대문자로
U 뒤에 오는 모든 글자를 소문자로
Q 뒤에 오는 모든 특수문자에(non-alphanumeric) 를 붙여서
E U, L, Q의 끝을 표시


마지막으로 back-quote가 있는데, 이것은 문자열이라기보다는 문자열을 shell에서 실행한 결과 값을 저장하게 된다. back-quote는 back-tick이라고 부르기도 한다.
 

$time_of_today = `date`;
print $time_of_today;  # 출력 결과 Mon Apr 27 20:59:04 KST 1998


위와 같은 코드에서는 Perl이 date라는 프로그램을 실행하여 나오는 값이 변수에 저장되게 된다. back-quote문자열에서는 double-quote문자열에서와 마찬가지로 interpolation이 되어진다. 다음 코드는 shell에서 "ls | grep doc"를 실행한 것과 같은 결과를 출력하는 것이다.
 

$keyword = 'doc';
print `ls | grep $keyword`;


출력결과
 

jdbcprog.doc
vi.doc
xprog.doc


다음의 표는 quotation의 여러 가지 방법에 대해 정리한 것이다.
 

관습적 사용      일반적 사용      의미   interpolation여부
''   q//   문자열상수 x
""   qq//   문자열상수 o
``   qx//   실행명령 o
()   qw//   list   x
//   m//   pattern match    o
s///   s///   substitution     o
y///   tr///   translation      x


일반적 사용에서 q 다음에 나와있는 backslash(/)는 다른 문자로 바꾸어 사용할 수 있다. 자세한 것은 뒤에 나오는 소단원을 참고하도록 하고 간단한 예제를 통해 그 사용법을 알아보도록 하자.
 

$abc = q$I'm a boy. You're a girl.$;
$def = qq#Hello,neveryone#;
$ghi = q&
            while (test != 0) {
                    i++;
                printf("%d", i);
            }
&;


변수 abc는 $를 single-quote(') 대신으로 사용하였고, def는 #을 double-quote(") 대신으로 사용하였다. ghi의 경우, multi-line string을 지정하는데, single-quote(') 대신에 &기호를 사용하였다.

  3) scalar variable

scalar variable은 하나의 값을 가지는 변수를 뜻하고 다음에서 살펴 볼 vector variable과는 상대되는 표현이다. scalar variable은 앞에서 보았던 수치나 문자열과 같은 값을 오로지 하나만 가지는 값이다. 일반적으로 scalar variable은 $기호를 변수 이름 앞에 붙여 vector variable과 구분한다. Perl에서는 C에서와 마찬가지로 변수의 이름은 대소문자가 달라지면 전혀 다른 변수로 인식된다. 다음의 변수들은 모두 다르게 구분되는 scalar 변수들이다.

 

$abc
$ABC
$account_number_of_bank1
$account_number_of_bank2
$xyz001


scalar variable에 대해서 산술 연산자 등의 일반적인 연산자를 수행할 수 있다.

  4) vector variable

vector variable은 크게 세 가지 종류로 나눌 수 있는데, array와 associative array가 그것이다. Perl에서는 array는 list라는 이름으로, associative array는 hash라는 이름으로 일컬어지기도 한다.

list는 변수 이름 앞에 @표시를 하여 구분하고, hash는 %기호를 사용한다. 다음의 변수들은 각각 list와 hash의 예이다.

 

@certain_list = ("abc", "def", "123");
@quoted_list = qw(
  1, 2, 3,     
  4, 5, 6,
  7, 8,
);
%a_special_hash = (('test', "hello"), ('verify', 123));
%list_like_hash = ("red", 0xf00, "green", 0x0f0, "blue", 0x00f);
%another_special_hash = (
  red => 0xf00,
  green => 0xf00,
  blue => 0xf00,
);


vector variable은 다른 vector 형태의 variable을 포함하여 지정할 수 있다.
 

@next_list = ("abc", "def", "123", @previous_list);
%general_hash = (%a_special_hash, %list_like_hash);


vector variable은 scalar variable과는 달리 주의해서 사용해야 한다. quotation을 하는 경우와 아닌 경우가 다르고, 그 변수를 vector차원에서 다루는 경우와 그의 원소인 scalar차원에서 다루는 경우가 다르다. 다음 예제를 참고하여 차이점을 알아보도록 하자.
 

print "@certain_list";
print @certain_list;


두 문장의 출력 결과는 다음과 같다. print는 첫 번째의 경우를 list를 quotation한 것으로 간주하여 space를 출력해주고, 두 번째의 경우를 list로 간주하여 space없이 붙여서 출력해준다.
 

abc def 123
abcdef123


다음의 hash에 관련된 코드는 list와 같을까?
 

print "%a_special_hash";
print %a_special_hash;


list와는 달리 hash의 경우 interpolation이 일어나지 않음을 알 수 있다.
 

testhelloverify123
%a_special_hash


일반적인 의미에서의 "hash"란 두개의 값을 한 쌍으로 하여 저장하는 방식을 의미하는데, 여기서도 마찬가지로 hash는 key와 value를 구분하여 사용하게 된다. 앞에서 제시한 예에서는 "test"와 "verify", "red", "green", "blue"등이 key가 되고, "hello", 123, 0xf00, 0x0f0, 0x00f등이 그 key로 찾을 수 있는 value가 된다.
 

print $a_special_hash{'test'};
$key = 'verify';
print $a_special_hash{$key};


list의 경우에는 각각의 value를 처리하기 위해 index(subscript)를 사용한다. 이런 경우에는 list 중의 하나의 scalar variable에 대한 연산이 된다. C에서의 index와는 달리 Perl에서는 ..를 이용해서 range(범위)에 대한 연산도 가능하다.
 

print $colors[0];
$id_list[3]++;
print @month[8..11];           # @month[8..11]는 @month[8, 9, 10, 11]과 같다.
$b = $namelist[$number];


list 단위의 연산도 가능하다. 대표적인 것으로 list assignment가 있다.
 

($a, $b, $c) = (3, 4, 5);
@array = ('a', 'b', 'c', 'd');


vector variable 중에는 어떤 값도 가지지 않는 변수가 존재할 수 있는데, 이런 것을 null list라고 하며 ()로 표현한다.
 

@a = ();


특히 null list는 0, "0"과 함께 조건문에서 false expression을 의미하는 것으로 사용된다.

list의 마지막 인덱스를 알기 위해서는 $#기호를 변수이름 앞에 붙이면 된다. list 중에 포함되어 있는 원소의 개수를 알기 위해서는 scalar()함수를 사용한다. 인덱스는 0부터 매겨지기 때문에 일반적으로 $#list + 1 == scalar(@list)가 성립한다.

  5) 특수한 변수(Special variable)

a) Regular expression variable

우선 $*라는 특수변수가 multi-line mode를 위해 Perl 4까지 사용되었는데, Perl 5부터는 regular expression을 사용할 때 modifier를 사용하는 방식으로 바뀌면서 더 이상 사용되지 않게 되었다. 이것은 패턴 매칭의 regular expression부분을 참고하도록 한다.

special variable들은 기억하기 쉽도록 mnemonic name을 가지고 있는데, 그러한 기능을 사용하려면 Perl 프로그램의 앞부분에서

 

use English;


로 지정해주어야 한다. 다음은 각각의 special variable과 그 역할에 대해 정리해놓은 표이다. pattern match와 관련된 변수들은 지역변수(local special variable)임을 기억하도록 하자.
 

$digit 27242, 17072,

 

 

출처 : http://ttongfly.net/zbxe/?document_srl=45342&mid=scriptprogramming&listStyle=&cpage=

 

Perl 문법설명

 

 

다음의 기사는 월간 프로그램 세계 1997년 6월호 특집기사로 실렸던 것입니다. 특집기사는 총 3부로 이루어져 있는데, 1부는 Perl의 소개, 2부는 Perl의 문법, 3부는 Perl을 이용한 CGI 예제 프로그램 작성으로 구성되어 있습니다. 제가 맡은 부분은 2부였고 총 분량의 절반에 해당합니다. 1부와 3부는 김대신(웹데이타뱅크)씨가 맡으셨습니다. 다음의 글은 제가 초안으로 작성한 텍스트 파일을 HTML문서로 약간 손을 본 것입니다.

차례

 

  1. 소개

  2. Perl의 문법
    1. 변수(Variable)
      1.   
      2. 수치(number)
          
      3. 문자열(string)
          
      4. scalar variable
          
      5. vector variable
          
      6. 특수한 변수(Special variable)
          
      7. 레퍼런스(reference)
          
      8. 배열의 배열, 해시의 배열, 배열의 해시
    2. 식(Expression)
      1.   
      2. 기본 연산자
          
      3. 추가 연산자
          
      4. 기본 입출력 연산자
          
      5. 비교 연산자
    3. Control Structure(제어 구조)
      1.   
      2. if
          
      3. unless
          
      4. while/until
          
      5. for
          
      6. foreach
          
      7. do/while, do/until
          
      8. goto
          
      9. next, last, redo
    4. 서브루틴(Subroutine)
      1.   
      2. 정의와 사용
          
      3. my와 local
    5. 패턴 매칭(Pattern Matching)
      1.   
      2. 정규 표현식(regular expression)
          
      3. match, substitute, translate
          
      4. 문자열 pattern 조작

소개

펄은 임의의 텍스트 파일들을 검색하고 그 파일에서 정보를 추출하며, 그 정보에 따라 보고서를 작성하는데 최적화된 언어이다. 또한 많은 시스템 관리 작업에 좋은 언어이다. 이 언어는 실용적일 수 있도록 만들어졌기 때문에 크기가 아주 작거나 아름답게 만들어지지지 는 않았지만 사용하기 쉽고 효율적이며 완벽하다고 말할 수 있다. 펄은 C와 sed와 awk와 sh 등의 사람들이 친숙하게 생각하는 언어들의 장점을 모아서 만든 것이기 때문에 배우기 어렵지 않다. 표현식은 거의 C와 비슷하며, 다른 유닉스 유틸리티와는 달리 용량 등의 제한이 없다. 주로 text를 처리하는데 뛰어난 능력을 보여주지만, 바이너리 자료를 다루는데 있어서도 데이터베이스를 만드는 기능이 있을 정도이다. sed나 awk를 사용하는데 문제가 발생한다면 C로 짜는 대신에 펄로 작성하면 스크립트를 거의 바꾸지 않아도 된다.

2부. 펄의 문법

Perl의 저자, Larry Wall이 말했던 것처럼 Perl은 한 가지 일을 하기 위해 10가지 방법을 제시하는 언어이다. 어떻게(how) 할 것인지가 중요한 게 아니라 무엇을(what) 할 것인지를 먼저 생각하고 프로그래밍을 해야 할 것이다. 그러나 다양한 표현 방식들을 많이 익히면 익힐수록 프로그래머에게 더 많은 가능성이 열리는 셈이다. 다음의 글은 독자들이 기본적인 C프로그래밍을 이해할 수 있고 유닉스의 shell기반의 작업들에 무지하지 않음을 가정하고 쓰여진 것이다. 그러나 가능하면 초보자들도 이해할 수 있도록 쉬운 표현과 예제를 이용하였다. 다음의 설명은 Perl 5를 기준으로 쓰여졌으나, Perl 4에서도 무난하게 사용 가능할 것이다.


1. 변수(Variable)

기본적으로 Perl은 변수에 대해, C와 같이 강력한 type checking을 하지 않는다. 다시 말해서 '값이 어떤 방식으로 저장되어있는가'는 '어떻게 사용할 것인가'와는 별개의 문제라는 것이다. C프로그래밍에 익숙한 사용자라면 int c = 'x'; 으로 정의된 변수 c가 문자형으로도 정수형으로도 사용 가능한 것을 떠올릴 수 있을 것이다. 그런 것을 확장해서 생각해보면 Perl의 변수들은 여러 형태로 사용할 수 있다. 그것은 Perl 인터프리터(interpreter;해석기)가 내부적으로 자동 변환해 주기 때문에 가능한 것이다.

  1) 수치(number)

Perl에는 정수형 수치는 존재하지 않는다. 모든 수치는 double-precision floating point형 수치로 존재한다. 다음과 같은 형태의 수치는 float literal(소수형 상수)이다.


 

111.25
23.25e91
-12.5e29
-12e-34
3.2E-23


다음과 같은 형태의 수치는 integer-literal(정수형 상수)이다. 숫자 앞에 0이나 0x를 붙여쓰게 되면 각각 8진수와 16진수를 의미하게 된다.

 

342
-2423
0377
-0xf0


  2) 문자열(string)

문자열은 이름이 뜻하듯이 연속된 문자들의 순열이다. 일반적인 ASCII 문자는 128개로 표현이 되지만, Perl에서는 특수문자가 표현되어야 하기 때문에 extended ASCII를 지원하여 문자열 내부의 각각의 글자는 0에서 255까지의 ASCII값을 가지게 된다. 문자열은 여러 형태의 두 quotation mark로 감싸서 표현할 수 있는데, 대표적인 케이스는 ''(single-quote)와 ""(double-quote), ``(back-quote)이다. single-quote사이에 들어가는 문자열은 interpolation을 하지 않고, double-quote사이에 들어가는 문자열은 interpolation을 하게 되는 차이점이 있다. 그러면 interpolation이란 무엇인가 예를 보면서 이해하도록 하자.

 

$str1 = 'hellonneveryone';
$str2 = "hellonneveryone";
print $str1 . "n";
print $str2 . "n";


두 문장은 quotation mark가 다르다는 점을 제외하고는 차이점이 없다. 그런데 출력결과는 다음과 같이 다르게 된다.
 

hellonneveryone  # 이것은 str1의 출력 결과이다.
                   
hello              # 이것은 str2의 출력 결과이다.

everyone


위와 같은 escape character뿐만 아니라 이미 정의되어진 변수들을 문자열 안에서 사용하는 경우에도 interpolation의 가능 여부에 따라 그 변수가 해석되기도 하고 그렇지 않기도 한다.
 

$str0 = "I'm a boy.";
$str1 = 'hello $str0';
$str2 = "hello $str0";
print $str1 . "n";
print $str2 . "n";


결과는 다음과 같다.
 

hello $str0       # str1의 출력 결과
hello I'm a boy.  # str2의 출력 결과


single-quote 문자열에서 single-quote(')를 표현하는 방법은 backslash뒤에 single-quote를 쓰는 것이다.
 

print 'I'm a boy.';  # 출력 결과 I'm a boy.


다음은 double-quote안에서 특별한 효과를 가지는 escape character의 종류와 그 의미에 관한 표이다.
 

n newline 다음 줄로
r return 줄의 맨 앞으로
t tab 탭
f formfeed
b backspace
v vertical tab
a alarm bell
e ESC
73 octal value 8진수(여기서는 73(8) = 7*8+3(10) = 59(10))
x7f hexadecimal value 16진수(여기서는 7f(16) = 7*16+15(10) = 127(10))
cC 제어문자 C
  backslash
" double-quote
l 다음 글자를 대문자로
L 다음 글자를 소문자로
u 뒤에 오는 모든 글자를 대문자로
U 뒤에 오는 모든 글자를 소문자로
Q 뒤에 오는 모든 특수문자에(non-alphanumeric) 를 붙여서
E U, L, Q의 끝을 표시


마지막으로 back-quote가 있는데, 이것은 문자열이라기보다는 문자열을 shell에서 실행한 결과 값을 저장하게 된다. back-quote는 back-tick이라고 부르기도 한다.
 

$time_of_today = `date`;
print $time_of_today;  # 출력 결과 Mon Apr 27 20:59:04 KST 1998


위와 같은 코드에서는 Perl이 date라는 프로그램을 실행하여 나오는 값이 변수에 저장되게 된다. back-quote문자열에서는 double-quote문자열에서와 마찬가지로 interpolation이 되어진다. 다음 코드는 shell에서 "ls | grep doc"를 실행한 것과 같은 결과를 출력하는 것이다.
 

$keyword = 'doc';
print `ls | grep $keyword`;


출력결과
 

jdbcprog.doc
vi.doc
xprog.doc


다음의 표는 quotation의 여러 가지 방법에 대해 정리한 것이다.
 

관습적 사용      일반적 사용      의미   interpolation여부
''   q//   문자열상수 x
""   qq//   문자열상수 o
``   qx//   실행명령 o
()   qw//   list   x
//   m//   pattern match    o
s///   s///   substitution     o
y///   tr///   translation      x


일반적 사용에서 q 다음에 나와있는 backslash(/)는 다른 문자로 바꾸어 사용할 수 있다. 자세한 것은 뒤에 나오는 소단원을 참고하도록 하고 간단한 예제를 통해 그 사용법을 알아보도록 하자.
 

$abc = q$I'm a boy. You're a girl.$;
$def = qq#Hello,neveryone#;
$ghi = q&
            while (test != 0) {
                    i++;
                printf("%d", i);
            }
&;


변수 abc는 $를 single-quote(') 대신으로 사용하였고, def는 #을 double-quote(") 대신으로 사용하였다. ghi의 경우, multi-line string을 지정하는데, single-quote(') 대신에 &기호를 사용하였다.

  3) scalar variable

scalar variable은 하나의 값을 가지는 변수를 뜻하고 다음에서 살펴 볼 vector variable과는 상대되는 표현이다. scalar variable은 앞에서 보았던 수치나 문자열과 같은 값을 오로지 하나만 가지는 값이다. 일반적으로 scalar variable은 $기호를 변수 이름 앞에 붙여 vector variable과 구분한다. Perl에서는 C에서와 마찬가지로 변수의 이름은 대소문자가 달라지면 전혀 다른 변수로 인식된다. 다음의 변수들은 모두 다르게 구분되는 scalar 변수들이다.

 

$abc
$ABC
$account_number_of_bank1
$account_number_of_bank2
$xyz001


scalar variable에 대해서 산술 연산자 등의 일반적인 연산자를 수행할 수 있다.

  4) vector variable

vector variable은 크게 세 가지 종류로 나눌 수 있는데, array와 associative array가 그것이다. Perl에서는 array는 list라는 이름으로, associative array는 hash라는 이름으로 일컬어지기도 한다.

list는 변수 이름 앞에 @표시를 하여 구분하고, hash는 %기호를 사용한다. 다음의 변수들은 각각 list와 hash의 예이다.

 

@certain_list = ("abc", "def", "123");
@quoted_list = qw(
  1, 2, 3,     
  4, 5, 6,
  7, 8,
);
%a_special_hash = (('test', "hello"), ('verify', 123));
%list_like_hash = ("red", 0xf00, "green", 0x0f0, "blue", 0x00f);
%another_special_hash = (
  red => 0xf00,
  green => 0xf00,
  blue => 0xf00,
);


vector variable은 다른 vector 형태의 variable을 포함하여 지정할 수 있다.
 

@next_list = ("abc", "def", "123", @previous_list);
%general_hash = (%a_special_hash, %list_like_hash);


vector variable은 scalar variable과는 달리 주의해서 사용해야 한다. quotation을 하는 경우와 아닌 경우가 다르고, 그 변수를 vector차원에서 다루는 경우와 그의 원소인 scalar차원에서 다루는 경우가 다르다. 다음 예제를 참고하여 차이점을 알아보도록 하자.
 

print "@certain_list";
print @certain_list;


두 문장의 출력 결과는 다음과 같다. print는 첫 번째의 경우를 list를 quotation한 것으로 간주하여 space를 출력해주고, 두 번째의 경우를 list로 간주하여 space없이 붙여서 출력해준다.
 

abc def 123
abcdef123


다음의 hash에 관련된 코드는 list와 같을까?
 

print "%a_special_hash";
print %a_special_hash;


list와는 달리 hash의 경우 interpolation이 일어나지 않음을 알 수 있다.
 

testhelloverify123
%a_special_hash


일반적인 의미에서의 "hash"란 두개의 값을 한 쌍으로 하여 저장하는 방식을 의미하는데, 여기서도 마찬가지로 hash는 key와 value를 구분하여 사용하게 된다. 앞에서 제시한 예에서는 "test"와 "verify", "red", "green", "blue"등이 key가 되고, "hello", 123, 0xf00, 0x0f0, 0x00f등이 그 key로 찾을 수 있는 value가 된다.
 

print $a_special_hash{'test'};
$key = 'verify';
print $a_special_hash{$key};


list의 경우에는 각각의 value를 처리하기 위해 index(subscript)를 사용한다. 이런 경우에는 list 중의 하나의 scalar variable에 대한 연산이 된다. C에서의 index와는 달리 Perl에서는 ..를 이용해서 range(범위)에 대한 연산도 가능하다.
 

print $colors[0];
$id_list[3]++;
print @month[8..11];           # @month[8..11]는 @month[8, 9, 10, 11]과 같다.
$b = $namelist[$number];


list 단위의 연산도 가능하다. 대표적인 것으로 list assignment가 있다.
 

($a, $b, $c) = (3, 4, 5);
@array = ('a', 'b', 'c', 'd');


vector variable 중에는 어떤 값도 가지지 않는 변수가 존재할 수 있는데, 이런 것을 null list라고 하며 ()로 표현한다.
 

@a = ();


특히 null list는 0, "0"과 함께 조건문에서 false expression을 의미하는 것으로 사용된다.

list의 마지막 인덱스를 알기 위해서는 $#기호를 변수이름 앞에 붙이면 된다. list 중에 포함되어 있는 원소의 개수를 알기 위해서는 scalar()함수를 사용한다. 인덱스는 0부터 매겨지기 때문에 일반적으로 $#list + 1 == scalar(@list)가 성립한다.

  5) 특수한 변수(Special variable)

a) Regular expression variable

우선 $*라는 특수변수가 multi-line mode를 위해 Perl 4까지 사용되었는데, Perl 5부터는 regular expression을 사용할 때 modifier를 사용하는 방식으로 바뀌면서 더 이상 사용되지 않게 되었다. 이것은 패턴 매칭의 regular expression부분을 참고하도록 한다.

special variable들은 기억하기 쉽도록 mnemonic name을 가지고 있는데, 그러한 기능을 사용하려면 Perl 프로그램의 앞부분에서

 

use English;


로 지정해주어야 한다. 다음은 각각의 special variable과 그 역할에 대해 정리해놓은 표이다. pattern match와 관련된 변수들은 지역변수(local special variable)임을 기억하도록 하자.
 

$digit $1, $2, $3, ... 패턴 바깥에서, 매치(match)가 일어난 괄호 안의 substring을 지정할 때 사용되는 변수로 왼쪽 괄호'('의 순서대로 digit위치에 숫자가 사용된다.
digit 1, 2, 3, ... 패턴 안에서 사용되는 $digit형 변수와 같은 역할을 한다.
$& $MATCH 가장 마지막에 매치가 일어난 substring을 지정하는 변수
$` $PREMATCH $MATCH 앞쪽의 substring을 지정하는 변수
$' $POSTMATCH $MATCH 뒤쪽의 substring을 지정하는 변수
$+ $LAST_PAREN_MATCH 패턴 내의 가장 뒤쪽에 위치한 괄호 안의 substring을 지정하는 변수로 alternative matching 사용시 편리하다.
$* $MULTILINE_MATCHING default로 0의 값을 가지면서 single-line matching mode를 지정하고, 1의 값을 가지게 되면 multi-line matching mode를 지정한다.


여기서 제시된 여러 special variable 중에서 $*만이 값을 바꿀 수 있는 변수이고, 나머지 변수들은 모두 read-only의 속성을 가지는 변수이다.

다음은 local special variable을 사용한 예제로서, default input variable인 $_에서 pattern matching을 수행하고 match가 일어난 부분과 바로 앞부분, 바로 뒷부분이 $`, $&, $'에 저장됨을 보여준다.

 

$_ = 'abcdefghi';
/def/;
print "$`:$&:$'n";


출력결과는 abc:def:ghi 이다.

다음은 위치상으로 가장 뒤쪽에서 매치가 일어나는 부분은 Revision: 뒤쪽의 문자열이며, 이 문자열은 $+에 저장됨을 알 수 있는 예제이다. pattern matching이 성공적으로 수행되면(match가 일어나면) $rev에 revision값을 저장하게 된다.

 

/Version: (.*)|Revision: (.*)/ && ($rev = $+);


b) Per-Filehandle variable

Filehanle이란 사용자가 작성한 Perl program과 외부에 존재하는 파일사이의 I/O 연결을 위한 Perl program의 이름이다. Unix의 표준 file-descriptor를 지원하기 위한 filehandle로는 STDIN(표준입력)와 STDOUT(표준출력), STDERR(표준에러출력)가 있다. 이외에도 사용자가 특정한 파일을 다루기 위해 filehandle을 지정할 수 있다. 자세한 내용은 파일조작에 관련된 절을 참고하도록 하자.

method HANDLE EXPR 또는 HANDLE->method(EXPR)과 같은 형식으로 지정한 다음에 다음과 같은 코드를 사용하여 다음의 변수들을 지정 또는 변경할 수 있다. HANDLE위치에는 사용할 filehandle의 이름을 지정하면 되고, EXPR위치에는 현재 filehandle의 속성의 값을 지정할 수 있다. 사용가능한 method는 아래 정리되어 있다.

 

use FileHandle;
$| $OUTPUT_FLUSH_NUMBER autoflush HANDLE EXPR 값을 0이 아닌 값으로 지정하면, write또는 print문장 후에 fflush(3)함수를 호출하여 현재 선택된 output channel로 출력을 강제한다.
$% $FORMAT_PAGE_NUMBER format_page_nubmer HANDLE EXPR   현재 선택된 output channel의 현재 page 번호이다.
$= $FORMAT_LINES_PER_PAGE format_lines_per_page HANDLE EXPR 현재 선택된 output channel의 현재 page 길이(프린트 가능한 line의 수)이다.
$- $FORMAT_LINES_LEFT format_lines_left HANDLE EXPR   현재 선택된 output channel의 남아있는 line의 수이다.
$~ $FORMAT_NAME format_name HANDLE EXPR           현재 선택된 output channel의 현재 report format의 이름이다.
$~ $FORMAT_TOP_NAME format_top_name HANDLE EXPR 현재 선택된 output channel의 현재 top-of-page format의 이름이다.


다음은 관련된 특수한 변수들의 사용 예제이다.
 

use FileHandle;
use English;

print '$| = '."$|n";
print '$% = '."$%n";
print '$- = '."$-n";
print '$~ = '."$~n";
print '$^ = '."$^ n";

print '$= = '."$=n";<
print '$= = '."$FORMAT_LINES_PER_PAGEn";
format_lines_per_page STDOUT 30;
print '$= = '."$FORMAT_LINES_PER_PAGEn";
print '$= = '."$=n";


특정 filehandle인 HANDLE에 per-filehandle special variable을 지정해주는 예제는 다음과 같다.
 

select((select(HANDLE), $| = 1, $^ = 'mytop')[0]);


c) Global Special variable
 

$_ $ARG default input string, standard input이나 첫 번째 argument로 넘겨진 파일을 읽을 때 넘겨져 오는 string을 의미한다.
$. $INPUT_LINE_NUMBER $NR 마지막으로 읽힌 filehandle의 현재 input line number이다. 여러 argument로 넘겨진 파일들을 구분하지 않으므로, 다른 파일로 바뀌더라도 line number가 계속 증가하게 된다.
$/ $INPUT_RECORD_SEPARATOR $RS input record를 구분해주는 string을 의미하며 default값은 newline character이다.
$, $OUTPUT_FIELD_SEPARATOR $OFS output field를 구분해주는 string이며, print 연산자에서 사용된다. 일반적으로는 comma(,)가 separator로 사용된다.
$ $OUTPUT_RECORD_SEPARATOR $ORS output record를 구분해주는 string으로서 보통은 print 연산자가 record뒤에 newline내지는 record separator을 찍어주지 않기 때문에 필요할 경우, 지정하여야 한다.
$" $LIST_SEPARATOR list의 구분자로 사용되는 string을 지정하는 변수이다. 기본 값으로 space가 지정되어 있다.
$; $SUBSCRIPT_SEPARATOR $SUBSEP 다차원 배열을 만들기 위해 list내에서 변수들을 나열할 경우, 그 변수들이 하나의 record로 인식되어야 하는데, 그것을 위해서 list내의 각 변수들을 join하는데 사용하는 변수이다.
$^L $FORMAT_FORMFEED
format_formfeed HANDLE EXPR
print할 때, output의 format에서 formfeed로 사용될 string을 지정하는 변수로서, 기본 값은 "f"이다.
$: $FORMAT_LINE_BREAK_CHARACTERS
format_line_break_characters HANDLE EXPR
연속적인 field를 잘라야 하는 경우 그 기준이 되는 character의 집합을 정의하는 변수이다. default로 "n-", 다시 말해서 newline과 hyphen이 사용된다.
$^A $ACCUMULATOR format line을 위한 write accumulator의 현재 값을 지정하는 변수이다.
$# $OFMT Perl5에서는 사용되지 않는, 이전 버전과의 호환성을 위해 제공되는 변수로, 숫자를 출력하기 위한 output format을 지정하는 변수이다. 초기 값은 %.14g 이다.
$? $CHILD_ERROR 마지막 실행 문에서 return되는 status값이다. 상위 8비트는 child process의 exit value이고, 하위 8비트는 어떤 signal을 받았는지와 core dump가 일어났는지의 여부에 대한 정보를 포함한다.
$! $OS_ERROR $ERRNO error에 관한 정보를 포함하는 변수로서, 사용되는 문맥에 따라 error 번호 또는 error string을 보여주게 된다.
$@ $EVAL_ERROR eval 명령으로부터 발생하는 error message를 담는 변수이다. null로 값이 지정될 경우 성공적으로 실행되었음을 의미한다.
$$ $PROCESS_ID $PID 현재 script를 실행하고 있는 Perl프로그램의 process id(번호)를 지니고 있는 변수이다.
$< $REAL_USER_ID $UID 현재 process의 real user id(uid)를 지닌 변수로서, process를 실행시킨 사용자의 id를 의미한다.
$> $EFFECTIVE_USER_ID $EUID 현재 process의 effective user id(euid)를 지닌 변수로서, process의 원래 소유자의 id를 의미한다. 일반적인 process의 경우, uid와 같은 값을 가지지만, setuid bit가 켜져 있는 실행파일의 경우, uid는 실행자의 id로, euid는 파일 소유자의 것으로 지정된다.
$( $REAL_GROUP_ID $GID 현재 process의 real group id(gid)를 지정하는 변수이다.
$) $EFFECTIVE_GROUP_ID $EGID 현재 process의 effective group id(egid)를 지정하는 변수이다.
$0 $PROGRAM_NAME 현재 실행중인 Perl script의 이름을 지정하는 변수이다.
$[   배열의 첫 번째 원소의 index, 또는 substring의 첫 번째 글자의 index를 지정하는 변수이다. 기본적으로는 0번 원소부터 배열이 시작하지만, 1번 원소부터 배열이 시작하도록 1로 값을 바꿀 수 있다.
$] $PERL_VERSION Perl의 version과 patch level을 알려주는 변수로서, 5.004는 5번째 version에 4번째 patch level임을 의미한다.
$^D $DEBUGGING debugging flag(-D switch)가 켜져 있는지에 관한 정보를 담고 있는 변수이다.
$^F $SYSTEM_FD_MAX 현재 open되어 사용되고 있는 file descriptor의 최대 번호를 지정하는 변수이다. 보통 프로그램이 시작하게 되면 자동으로 0, 1, 2번이 STDIN, STDOUT, STDERR로 설정된다.
$^H   Perl compiler의 내부 컴파일 힌트에 관한 정보를 담는 변수이다.
$^I $INPLACE_EDIT inplace-edit extension의 값을 저장하는 변수이다. 이 값은 -i switch에 의해 지정된다.
$^O $OSNAME 현재 사용되고 있는 Operating System의 이름을 저장하는 변수이다.
$^P $PERLDB Perl debugger가 자신을 debug하지 않도록 꺼주는 내부 flag 변수이다.
$^T $BASETIME script가 실행되기 시작한 시각을 지정하는 변수이다. Unix system에서는 70년 1월 1일 0시 0분 0초(epoch)로부터의, 초단위 시간이다.
$^W $WARNING -w switch에 의해 지정되는 warning(경고) 여부의 값을 저장하는 변수이다.
$^X $EXECUTABLE_NAME Perl 바이너리가 실행 시에 가지게 되는 이름을 지정하는 변수이다.
$ARGV   argument로 넘겨져 들어온 파일의 이름이다.


다음의 예제는 동일한 의미를 가지는 코드이다.
 

$foo{$a, $b, $c}
$foo{join($;, $a, $b, $c)}


d) Global special array
 

@ARGV 넘겨져 들어온 command-line argument의 list를 저장하는 변수이다.
@INC do, require, use등의 operator를 사용할 때 필요한 Perl script를 찾는 디렉토리를 지정하는 변수이다. -I switch를 사용하여 지정된다. lib module을 사용하여도 지정 가능하다.
@F -a switch를 사용한 경우에, input line을 분리해 넣어줄 변수의 array를 지정하는 list 변수이다.
%INC module로 사용될 Perl script의 이름과 그 script의 절대경로를 저장해놓은 hash 변수이다.
%ENV shell에서 넘겨져 온 hash type의 환경변수이다. 환경변수의 이름과 그 값을 hash해 놓았다.
%SIG signal과 그에 해당하는 signal handler를 지정하는 hash 변수이다.


다음은 환경 변수를 지정하는 예제이다.
 

$ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin";


signal handler를 사용하는 예제를 참고하도록 하라. Ctrl-C를 눌러 interrupt를 걸게 되면 프로그램이 중단되게 되는데 INT signal을 가로채서 특정한 함수(signal handler)를 실행시키도록 할 수 있다.
 

sub sighandler {
  local($sig) = @_;
  print "Closing log file...n";
  close(LOG);
  exit(0);
}
$SIG{'INT'} = 'handler';


e) Global special Filehandles
 

ARGV @ARGV에서 저장된 argument로 넘겨진 file들을 다루는 filehandle이다. 는 <>로 줄여서 사용 가능하다.
STDERR standard error에 대한 filehandle이다.
STDIN standard input에 대한 filehandle이다.
STDOUT standard output에 대한 filehandle이다.
DATA Perl script에서 __END__라는 token뒤쪽에 나오는 모든 자료에 대한 filehandle이다.
_(underline) 마지막으로 다루었던 파일에 대한 정보를 cache로 저장하고 있는 filehandle이다.


  6) 레퍼런스(reference)

'레퍼런스'란 우리말로 옮기자면 '참조'라고 할 수 있다. 어떤 변수가 존재하고 그 이름을 저장함으로써 원래의 변수를 '참조'하는 다른 변수가 존재한다면 그 변수를 symbolic reference라고 한다. 반면에 hard reference라는 것도 있는데, 이것은 이름을 통해서가 아니라 실제의 값을 통해서 참조하게 된다. 여기에서는 hard reference에 더 중점을 두어 자세히 설명하려고 한다.

reference와 관련된 용어들에 대해서 잠깐 설명을 하고 넘어가자. reference를 만드는 것을 referece한다고 하면, 반대의 과정, 즉 참조 대상이 되는 변수나 상수의 값을 꺼내오는 것을 dereference한다고 한다. reference의 대상이 되는 것을 thingy(referent)라고 부른다. Perl의 저자인 Larry Wall이 thingy라는 표현을 고집하므로 여기서도 thingy라는 표현을 사용하도록 하겠다.

a) hard reference

hard reference가 가리키는 대상을 Perl에서는 흔히 thingy라고 지칭하는데, 이 thingy에 따라, hard reference를 만드는 방법은 조금씩 달라진다. 대상은 어떤 값이라도 가능한데, 여기서는 이름 있는 변수(named variable)와 서브루틴(named subroutine), 이름 없는 배열(anonymous array), 이름 없는 hash(anonymous hash), 이름 없는 서브루틴(anonymous subroutine), 파일핸들(filehandle)에 대해서 살펴보기로 하자.

우선 대개의 변수와 서브루틴은 이름을 가진다. 그러므로 이러한 일반적인 변수나 서브루틴에 대한 reference가 많이 필요하게 되며, hard reference는 (backslash)연산자를 사용함으로써 만들 수 있다.

 

$scalarref = $foo;  # $foo는 일반변수, 는 reference하는 연산자
$constref = 3.24;  # hard reference는 값에 대한 reference이다.
$arrayref = @array1; 
$hashref = %hash2; 
$globref = *STDOUT;  # *는 typeglob이며, 모든 타입을 가리킨다.
$subref = &subroutine3; 


간단히 일반화해보면, 어떤 형태의 변수나 상수에 대해서 그 앞에 연산자를 붙여주면 hard reference가 되는 것이다. reference를 통해서 그 값을 사용하기 위해서는 $, &, @, % 연산자 중의 하나를 reference변수 앞에 붙여주면 된다. reference는 그 대상(thingy)가 어떤 타입인지를 신경 쓰지 않기 때문에, 사용자가 타입 캐스팅을 하듯이 타입연산자인 $, %, &, @ 등의 연산자를 지정하는 것이 필수적이다.
 

print $$scalarref;  # print $foo;와 동일하다.
$$constref   # 3.24와 동일하다.
$$hashref{'key1'}   # $hash2{'key1'}과 동일하다.
&$subref;   # subroutine3를 호출하게 된다.
shift(@$arrayref);  # @array1에 대해 shift연산을 하는 것과 같다.


reference변수를 다시 reference할 수 있는데, 이럴 때에는 필요한 만큼 연산을 붙여 줄 수 있고, 값을 꺼낼 때에는 타입연산자의 수가 연산자의 수보다 하나 더 많은가를 확인해야 한다.
 

$multiref = 123;  # 123에 대해 연산을 4번 시행
print $$$$$multiref;  # $multiref에 대해서 $연산을 4번 시행


이번에는 이름 없는 배열과 해시와 서브루틴을 참조하는 hard reference를 다루는 법에 대해서 알아보도록 하자. 여기서 이름이 없다는 표현은, 이미 만들어져서 이름을 가지고 있는 변수나 상수의 값을 참조하는 게 아니라 reference를 만들면서 그것이 참조하는 thingy를 만들기 때문에 이름을 지어주지 못했다는 의미이다.
 

$arrayref = [1, 2, [3, 4, 5]];  # anonymous array reference
$hashref = {
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
};


$subref = sub { 
  print "When Harry met Sallyn"; # anonymous subroutine reference
};



위의 예제를 살펴보면, reference는 보이지 않고, 보통 variable에 값을 대입해 준 것처럼 보인다. 그러나 실제 assignment는 다음과 같다. 잘 비교해보도록 하자. 연산자로 사용되는 기호들이 약간씩 다르다는 것을 알게 될 것이다.
 

@array = (1, 2, (3, 4, 5));
%hash = (
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
);
&subroutine1;
sub subroutine1 {
  print "Sleepless in Seattlen"; # anonymous subroutine reference
};


두 예제를 비교해 본 바와 같이, anonymous array reference는 [ ]을, anonymous hash reference는 { }를, anonymous subroutine reference는 sub { }를 연산자로 사용한다는 것을 알 수 있다.

b) hard reference in nested data structure

$연산자로 dereference하는 것 이외에도, ->연산자(arrow operator)를 사용해서 array나 hash의 값을 dereference하는 방법도 있는데, 이러한 방법들은 '배열의 배열'을 구현할 때 긴요하게 쓰인다. 다음은 같은 효과를 내는 연산자 사용에 대한 예이다.

 

$$arrayref[0] = "first";
${$arrayref}[0] = "first";
$arrayref->[0] = "first";

$$hashref{'key2'} = "McLean";
${$hashref}{'key2'} = "McLean";
$hashref->{'key2'} = "McLean";


->연산자는 dereference의 기능을 $연산자보다 더 직관적으로 제시하기 때문에 C프로그래밍에 익숙한 사용자에게 유용할 것이다. 다음은 ->연산자를 이용한 1차원 배열의 원소를 dereference하고, '배열의 배열'내의 원소를 dereference하는 방법을 보인 예이다.
 

$arrayref->[3] = "list-item1";

$arrayref->[3]->[4] = "multi-dimensional-item2";
$arrayref->[3][4] = "multi-dimensional-item2";
$$arrayref[3][4] = "multi-dimensional-item2";


C프로그래머에게는 '배열의 배열'을 나타내는 위의 표현 중에서 마지막 것이 친숙해 보일 수 있으나, Perl에서는 []연산자가 우선 순위(precedence)가 낮아서 reference가 어떻게 사용되고 있는지를 알아보기가 어렵다는 이유로 권하지 않는 방법이다. 그 위의 두 가지 방법을 이용하여 다중 배열을 나타내기로 한다.
 

$ref_list_of_list = [
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
];
print $ref_list_of_list[0][2];      # terminator가 출력된다.
print $ref_list_of_list->[2][1];    # electronics가 출력된다.
print $ref_list_of_list->[1]->[3];  # signed가 출력된다.


만약 for loop를 사용해서 모든 원소를 출력하기를 원한다면, 각 sub list가 가지고 있는 원소의 개수를 알아야 하는데, length()함수를 써서 원소의 개수를 구해 내거나, $#연산자를 사용하여 리스트변수의 마지막 인덱스를 얻을 수 있다.

b) symbolic reference

symbolic reference는 reference가 가리키고 있는(여기서는 thingy가 아님을 유의할 것) 변수의 이름을 문자열로 해서 저장하게 된다. 다시 말해서 변수의 이름을 가진다는 것은 symbolic reference를 만드는 것이다. hard reference가 thingy를 직접 참고하는 것에 반해서 symbolic reference는 변수의 이름을 통해서 그 값에 접근하게 된다. 그러므로 항상 named variable에 대해서만 symbolic reference를 만들 수 있는 것이다.

symbolic reference를 만드는 것은 단순히 변수의 이름을 지정하기만 하면 되며, 그 사용법도 hard reference와 다르지 않다. 타입연산자를 앞에 붙여주면 그 값을 취할 수 있게 된다.

 

$var1 = "test";
$sr = "var1";
$$sr = "verify"; # $var1 eq "verify"

@var2 = ("hello", "program", "world");
$sr = "var2";
push(@$sr, "perl"); # @var2 eq ('hello', 'program', 'world', 'perl')


  7) 배열의 배열, 해시의 배열, 배열의 해시

배열의 배열은 사실상 Perl에서 제공하려고 의도하는 것은 아니다. Perl은 단순히 1차원의 배열만을 제공하는데, C와는 달리 scalar값이 놓일 위치에 vector형 변수가 놓일 수 있으므로 자연스럽게 배열의 배열, 해시의 배열, 배열의 해시 등과 같은 복합적인 data structure를 만들 수 있다.

a) 배열의 배열

다음과 같은 코드를 실행시켜 보자. 아마 아무 출력도 없을 것이다. 그 이유는 Perl이 1차원 배열만을 제공하기 때문에 $list_of_list[0][2]와 같은 형식은 무시되기 때문이다.(-w 스위치를 사용하면 warning을 볼 수 있다.)

 

@list_of_list = (
  ("separator", "delimiter", "terminator"),
  ("long", "short", "int", "signed", "unsigned"),
  ("physics", "chemistry", "computer"),
);


print $list_of_list[0][2]; 
print $list_of_list[2][1]; 
print $list_of_list[1][3];


2차원 배열을 구현하기 위해서는 reference를 이용해야 한다.
 

@list_of_list = (
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
);
print $list_of_list[0][2];  # terminator가 출력된다.
print $list_of_list[2][1];  # electronics가 출력된다.
print $list_of_list[1][3];  # signed가 출력된다.


b) 배열의 해시

리스트를 해시 값으로 사용하여 해시를 만드는 것도 비슷한 방법에 의해 가능하다.

 

%hash_of_list = (
  token => ["separator", "delimiter", "terminator"],
  type => ["long", "short", "int", "signed", "unsigned"],
  science => ["physics", "chemistry", "computer"],
);

print $hash_of_list{'token'}->[1]; # delimiter가 출력된다.
print $hash_of_list{'type'}[0];    # long이 출력된다.
print $hash_of_list{science};      # ARRAY(0xb2074)같은 정보가 출력된다.
print $hash_of_list{science}->[2]; # computer이 출력된다.
print @$hash_of_list{science};     # 아무 것도 출력되지 않는다.
print @{$hash_of_list{science}};   # physicschemistrycomputer 출력


c) 해시의 해시
 

%hash_of_hash = (
  token => {
    s => "separator", 
    d => "delimiter",
    t => "terminator"
  },
  type => {
    l => "long",
    s => "short",
    i => "int"
  },
  science => {
    e => "chemistry", 
    c => "computer",
  },
);

print $hash_of_hash{token}->{s}; # separator 출력
print $hash_of_hash{type}{i};    # int 출력
print $hash_of_hash{science};    # HASH(0xb205c)같은 정보가 출력된다.


다만 주의할 것은 해시나 리스트는 해시의 키(key)로 사용할 수 없다는 것이다. 이유는 key는 단순한 문자열로 취급이 되기 때문이다. 리스트나 해시를 넣는다고 해도 문자열 이상의 의미를 가지지는 못하게 된다.

2. 식(Expression)

  1) 기본 연산자

a) 수치 연산자

Perl은 수치에 대해서 사칙연산을 기본적으로 제공한다. +, -, *, /가 그에 해당하는 연산자이다. 그리고 FORTRAN과 같이 **에 의한 거듭제곱 연산도 가능하다. 나머지를 구하는 연산도 있는데, %를 연산자(operator)로 사용하며, 피연산자(operand) 모두를 정수로 취급한다. 반면에 나누기 연산자인 /는 피연산자 모두를 실수로 취급한다. 논리연산자인 <, <=, ==, >=, >, !도 사용 가능하다.

다음은 수치 연산자의 사용 예이다.
 

2 + 3  # 5
5.1 - 2.4 # 2.7
3 * 12  # 36
14 / 2  # 7
10.2 / 0.3 # 34
10 / 3  # 3.33333...

if (3 > 4) {
  print "3 is greater than 4.n";
} else {
  print "3 is not greater than 4.n";  # 비교문이 거짓이므로 여기가 실행됨
}


b) 문자열 연산자

문자열 연산자에는 C에서는 볼 수 없는 연산자들이 많이 등장한다. 우선은 문자열들을 붙이는 연산자인 .(dot)이 있고, 문자열을 정수번 반복해서 붙여주는 x연산자도 있다. 다음의 예제를 참고하도록 하자.
 

$b = "Hello, ";
$c = "world";
$a = $b . $c;  # $a = "Hello, world"

$a = "boy";
$b = $a x 3;  # $b = "boyboyboy"
$c = $a x 4.2;  # $b = "boyboyboyboy", 4.2는 4로 cast된다.


c) 대입연산자(assignment operator)

대입연산자에는 C와 마찬가지로 =이 기본적인 연산자이다. 이밖에도 C에서 사용하는 대입연산자들은 거의 Perl에서 채택되어져 있다. +=, -=, *=, /=, &=, |=. ^=, %=가 그 예이다. 그 밖에도 .=, x=, ||=, **=, <<=, >>=의 연산자들이 있다. 이와 같은 대입연산자들은 %연산, .연산, x연산, ||연산을 수행한 후에 그 결과를 대입하는 것이므로 보충 설명이 없어도 이해에 어려움이 없을 것이다.
 

$a *= 3;  # $a = $a * 3;
$b .= "n";  # $b = $b . "n"
$c ||= 2;  # $c = $c || 2, $c가 2가 아니면 2의 값을 대입한다.


d) 연산자 우선 순위와 결합법칙

여러 연산자들의 결합순위와 우선 순위를 다음의 표로 정리해놓았다. 위쪽에 있는 연산자일수록 아래쪽 연산자들보다 우선 순위가 높다. 같은 줄에 있는 연산자들은 같은 우선 순위 가지게 되고 결합순위에 따라 연산의 순서가 정해진다.
 

결합순위 연산자
없음 ++ --
! ~ -(단항연산)
**
=~ !~
* / % x
+ -(이항연산) .
<< >>
없음 file test operator
없음 named unary operator
없음 < <= > >= lt le gt ge
없음 == != <=> eq ne cmp
&
| ^
&&
||
없음 ..
?:(삼항연산)
대입 연산자 (+= -= 등)
,
없음 list 연산자


e) 수치와 문자열 상호변환

Perl은 수치와 문자열, 정수와 실수 사이의 변환을 자동으로 해준다. 수치 앞 뒤쪽에 오는 쓸데없는 문자들을 자동으로 제거해주므로 다음과 같은 연산이 가능하다.
 

$a = "   3.5abcd" * 4;
print $a;   # 3.5 * 4 = 14가 출력된다.
$b = "3" + "4";   # $b = 7


Perl이 자동으로 변환해 주는 것은 문자열 또는 수치가 이중적인 의미를 가질 때, 앞쪽이나 뒤쪽에 위치하는 연산자가 필요로 하는 피연산자가 수치인가 문자열인가를 결정할 수 있기 때문이다.
 

print "boy" . (3 * 2);  # boy6가 출력된다.
print "boy" x (3 * 2);  # boyboyboyboyboyboy가 출력된다.


괄호 안의 3 * 2이 먼저 수치로서 계산이 된다. 수치로 인식되는 이유는 *이 수치를 피연산자로 가지기 때문이다. 다음에는 문자열을 결합시켜주는 . 연산자를 만나게 되므로 (3 * 2)의 결과인 6을 문자열로 변환시켜서 인식하게 된다. 이러한 방식으로 자동변환이 일어나게 되므로 프로그래머는 사소한 것에 신경 쓰지 않아도 된다.

  2) 추가 연산자

또 하나 프로그래머가 매달릴 필요가 없는 것은 연산자를 연산자로 볼 것인가 함수로 볼 것인가의 문제인데, Perl에서 제공되는 대개의 연산자는 연산자이면서 함수로 볼 수 있기 때문에 C처럼 ()를 반드시 써 줄 필요가 없다.

a) scalar operator
 

rand $a 0과 $a 사이의 임의의 값(random number)을 반환한다. 0이상 $a미만의 범위의 소수를 구하게 된다.
srand $a random number를 만들어 낼 때 사용하는 seed값을 지정한다. srand(time^$$)처럼 현재시간을 알려주는 time연산자와 현재 프로세스의 번호를 지정하는 $$변수를 넣어서 사용하기도 한다.
substr $a, $b, $c $a라는 문자열에서 $b의 offset위치에 $c개만큼의 원소를 지정하게 된다. substr을 이용해서 $a에 새로운 값을 넣어주거나 $a에서 원소를 꺼내올 수 있다. $c부분은 생략 가능하다.
index $a, $b, $c 문자열 $a에서 $b가 나타나는 위치(offset)을 알려준다. $c부분은 찾기 시작하는 위치를 지정하는 것인데, 생략되면 0의 값이 대신 사용된다.
chop $a chop은 $a의 마지막 글자를 제거하는 연산자이며 Perl 5에서는 다음의 chomp을 권장한다. $a는 리스트라도 처리할 수 있다.
chomp $a chomp는 chop의 안전한 버전이며, $a의 마지막 글자가 $/변수($INPUT_RECORD_SEPARATOR, $RS)의 값을 가지면 제거하는 역할을 한다. 대개는 입력에 붙어서 들어오는 newline character를 제거할 때 사용한다.


b) vector operator
 

shift @a 리스트 @a의 가장 앞쪽에 있는 원소를 꺼내준다.
unshift @a, $b $b를 @a의 가장 앞쪽에 쑤셔 넣어 준다.
pop @a @a의 가장 뒤쪽에 있는 원소를 꺼내준다.
push(@a, $b) @a의 가장 뒤쪽에 $b를 추가해준다.
splice @a, $b, $c, @d; @a의 offset이 $b되는 곳에서 $c개의 원소를 지정할 때 사용한다. @d가 사용되는 경우에는 @d를 $c개의 원소와 바꾸어준다. @d가 생략되면 $c개의 원소를 반환한다.
keys %a 해시 변수 %a의 key를 모아서 리스트 형태로 반환한다.
$a .. $b ..은 범위연산자(range operator)라고 하는데, $a에서 $b까지의 값을 리스트 형태로 반환한다. $a와 $b에 들어갈 수 있는 값은 정수나 문자이다. 문자열을 사용하면 그 사이에 존재할 수 있는 모든 문자열 조합을 만들어 주기도 하는데, 시스템의 자원을 낭비하기 쉬우므로 조심해야 한다.
, comma(,) 연산자는 리스트에서 separator로 사용되는 comma와는 다른 의미를 가진다. comma 연산자는 ,뒤쪽의 값을 반환한다. ,로 여러 개의 값이 나열되면 마지막 값이 리턴 된다.
sort @a 리스트변수 @a를 정렬해준다. sort의 기준을 제시하는 비교함수나 블럭을 지정할 수도 있는데, 리스트 앞에 지정해준다. 이 때 비교함수나 블럭에서는 <=>, cmp 연산자와 논리연산자등을 사용하여 +1, -1, 0등의 값을 반환하도록 한다.
reverse @a 리스트의 원소의 순서를 반대 방향으로 바꾸어준다.
grep PATTERN, @a
grep FILETEST, @a
리스트변수 @a를 읽어들여 패턴매치나 파일 테스트를 해서 성공할 경우, 그 리스트의 원소인 line이나 string을 반환한다.
join $b, @a @a의 원소들을 $b를 delimiter로 하여 묶어 하나의 문자열로 반환한다.
split PATTERN, $a, $b 문자열 $a를 PATTERN에 나오는 character를 delimiter로 해서 나누어 리스트형태로 반환한다. $b를 사용하게 되면 그 값에 해당하는 개수까지 원소들을 생성해준다.


c) file test operator

다음은 파일에 대한 조건식을 만드는 operator을 정리한 표이다. 다음의 테스트는 참/거짓의 값을 가지거나 특정한 결과 값을 return해 준다.
 

-r 파일을 읽을 수(readable) 있는가?
-w 파일을 쓸 수(writable) 있는가?
-x 파일을 실행시킬 수(executable) 있는가?
-o 파일이 $euid의 사용자 소유인가?
-R 파일이 $uid의 사용자에 의해 읽혀질 수 있는가?
-W 파일이 $uid의 사용자에 의해 쓰여질 수 있는가?
-X 파일이 $uid의 사용자에 의해 실행가능한가?
-O 파일이 $uid의 사용자 소유인가?
-e 파일이 존재하는가?
-z 파일의 크기가 0인가?
-s 파일의 크기(size)
-f 파일이 정규파일(디렉토리가 아닌)인가?
-d 파일이 디렉토리인가?
-l 파일이 symbolic link인가?
-p 파일이 FIFO와 같은 named pipe인가?
-S 파일이 socket인가?
-b 파일이 block special file인가?
-c 파일이 character special file인가?
-t filehandle이 tty(terminal)에 열려 있는가?
-u setuid bit이 켜져 있는 파일인가?
-g setgid bit이 켜져 있는 파일인가?
-k sticky bit이 켜져 있는 파일인가?
-T 파일이 텍스트(text) 파일인가?
-B 이진(binary) 파일인가?
-M file의 최종 수정 시간(modification time, mtime)
-A file의 최종 접근 시간(last access time, atime)
-C file의 최종 변경 시간(inode change time, ctime)


다음은 file test를 이용한 조건식의 예이다.
 

while (<>) {
  chomp;   # default input string의 마지막 n을 제거한다.
  next unless -f $_;  # 정규파일이 아닌 경우에는 다음으로 넘어간다.
}

stat($file);
print "Readablen" if -r _; # _는 마지막으로 사용된 filehandle이다.
print "Writablen" if -w _; # readable, writable, executable한지 체크한다.
print "Executablen" if -x _;

&newfile if -M $file < 5; # mtime이 5일 이내라면 서브루틴을 호출한다.


  3) 기본 입출력 연산자

입출력이란 프로그램이 자료를 외부세계에서 넘겨받고 그 자료를 처리한 결과를 외부세계에 넘겨주는 과정을 의미한다. Perl에서 가능한 방법은 파일을 이용한 것이고, 프로그래머는 filehandle이라는 것을 가지고 파일을 다룰 수 있게 된다. 파일을 열어서 filehandle을 지정하는 것은 open함수를 사용하면 되고, 더 이상 사용하지 않게 된 파일을 닫고 filehandle의 사용을 포기하는 것은 close함수를 이용하면 된다.

그러나 입출력 과정에 filehandle을 매번 사용한다는 것은 프로그램 작성에 상당한 불편을 안겨줄 것이다. 그리하여 Perl에서는 Unix시스템과 마찬가지로 표준입력(STDIN), 표준출력(STDOUT), 표준에러(STDERR)를 제공한다. 표준입력이란 키보드를 통해 자료를 입력받거나, 다른 프로그램에서 파이프나 redirection을 통해 자료를 넘겨받는 것이다. 반면에 표준출력은 print 연산이나 printf를 통해서 화면으로 결과를 출력하는 것이고, 표준에러는 화면에 에러메시지를 보여주는 것이다.

a) 입력

일반적으로 키보드로부터의 입력은
 

$input = ;
@input = ;


과 같은 형태로 받아들일 수 있다. $input이나 @input에는 사용자가 키보드를 통해 눌렀던 모든 키 입력이 문자열 또는 리스트의 형태로 저장된다.

Perl에서 즐겨 사용되는 입력방식에는 다음과 같은 것들이 있다. 짧은 코드에서 긴 코드까지 모두 같은 효과를 가지며, 문맥적으로 같은 의미를 가진다.
 

print while 
print $_ while ;
print $_ while definded($_ = );
for (;;) { print; }
for (;;) { print $_; }
while () { print; }
while () { print $_; }
while (defined($_ = )) { print $_ };


$_는 default input string을 저장하는 변수로서 대개의 연산자에서 생략 가능하다. 거꾸로 말해서, 연산자만 나오는 경우는 대개 $_를 염두에 둔 것이라고 볼 수 있다. 에서 들어온 모든 입력은 $_에 자동으로 저장된다. $_대신에 다른 변수를 사용해도 별로 상관은 없으나, 생략해서 사용할 수는 없다.

STDIN같은 표준입출력에 관련된 filehandle은 굳이 open의 과정이 필요 없으나, 일반적인 파일에 대한 filehandle은 open의 과정이 명시되어야 한다.

 

 

 

open(FILE, "test.c");
$_ = ;
print;

이 예제는 test.c라는 파일을 FILE이라는 filehandle을 통해서 다루게 되고 default input string에 한 줄 입력을 받아서 그것을 다시 출력해주는 작업을 하게 된다. 그러나 대개는 한 줄만 입력을 받는 게 아니라 파일 전체에 대해서 여러 줄의 입력을 받아야 하므로 loop안에서 사용하거나 리스트에 저장했다가 shift연산자를 사용하여 꺼내어 사용할 수 있다. 그러나 리스트에 파일의 큰 내용이 저장되는 것은 시스템에 부하를 주게 되므로 loop를 사용하는 방법을 익히도록 하자.

 

 

 

while ($input = ) {
  print "/* $input */n";
}

이 예제는 FILE을 통해 $input에 입력을 받고 그 line을 comment기호로 감싸는 작업을 수행하는 것이다.

Perl 프로그램이 filter로 사용되는 게 아니라면 대개는 프로그램의 argument로 파일 이름을 넘겨받아 사용하게 되는데, 이것은 아주 간단하다. 다음은 argument로 넘겨진 모든 파일을 열어서 한 줄씩 입력을 받아서 출력하는 예이다.

 

 

 

while (<>) {
  print;
}

이 코드는 다음과 동일한 의미를 가진다.

 

 

 

@ARGV = ('-') unless @ARGV;
while ($ARGV = shift) {
  open(ARGV, $ARGV) or warn "Can't open $ARGV: $!n";
  while () {
    print;
  }
}

argument로 넘겨받는 파일이름에 대해서는 신경쓸 필요 없이 <>만 사용하면 각 파일에 대해서 open하고 읽어들이는 과정이 모두 자동적으로 실행되는 것이다.

b) 출력

print연산을 사용하는 경우에는 default로 출력의 방향이 STDOUT으로 정해진다. 그러므로 다음의 세 문장은 같은 의미를 가진다.

 

 

 

print "Hello worldn";
print STDOUT "Hello worldn"; 
print STDOUT Hello, " ", world, "n";

STDOUT뒤에 ,를 찍지 않도록 주의하자. STDOUT은 출력 대상이 아니라 출력의 방향이기 때문이다.

특정 파일에 대해서 출력을 하기 위해서는 미리 쓰기 mode로 open을 해야 하고 그 이후에 print 연산에 출력 방향으로 그 파일의 filehandle을 지정하면 된다.

 

 

 

open(OUTPUT, "> output.log");
print OUTPUT "Result : All men are alive.n");

shell에서 사용하던 방식의 token을 이용한 출력방법도 있다. 이것을 here document 문법이라고 하며 token을 일종의 quote로 생각하는 것이다. 여러 줄에 걸쳐진 출력에 대해서 문서를 쓰듯이 출력할 수 있다는 게 장점이다.

 

 

 

print OUTPUT << EOF
But most of payload are lost. 
Estimation of loss are still being carried.
EOF

print 연산자는 EOF라는 토큰을 quote로 간주하고 두개 사이의 텍스트를 지정된 출력방향으로 내보내게 된다. 토큰에 따라서 보다 정교한 출력 방법이 있는데, 여기서는 몇 가지만 더 살펴보기로 하겠다.

 

 

 

print << "" x 10
Hello, world!

이 예제는 quote가 null string이므로(그러므로 ""조차 생략 가능하다.) 다음 줄만을 출력 대상으로 삼게 되고 print 연산을 10번 수행하게 된다.

 

 

 

print << `ANYTOKEN`
id
echo hello
ANYTOKEN

token을 감싸는 것이 back-quote(backtick)임에 유의하라. back-quote는 명령을 실행시켜주는 역할을 한다. 그러므로 두 토큰 사이에 존재하는 id와 echo hello라는 명령이 실행된 결과가 출력되게 된다.

c) 에러 출력

에러는 파일로 보낼 수도 있지만, STDERR로 모아서 보내는 것이 일반적이다. 그러므로 print의 출력방향을 STDERR로 명시하면 된다.

 

 

 

print STDERR "Can't find such a file!n";

  4) 비교 연산자

Perl에서는 문자열에서 사용되는 논리연산자와 수치에서 사용되는 논리연산자가 따로 제공된다. 다음의 표를 참조하라.

 

 

 

비교 표현식 수치연산자 문자열연산자
같은가? == eq
같지 않은가? != neq
보다 작은가? < lt
보다 큰가? > gt
같거나 작은가? <= le
같거나 큰가? >= ge
같지 않은가? <=> cmp

 

 

 

 

 

, ...
패턴 바깥에서, 매치(match)가 일어난 괄호 안의 substring을 지정할 때 사용되는 변수로 왼쪽 괄호'('의 순서대로 digit위치에 숫자가 사용된다.
digit 1, 2, 3, ... 패턴 안에서 사용되는 $digit형 변수와 같은 역할을 한다.
$& $MATCH 가장 마지막에 매치가 일어난 substring을 지정하는 변수
$` $PREMATCH $MATCH 앞쪽의 substring을 지정하는 변수
$' $POSTMATCH $MATCH 뒤쪽의 substring을 지정하는 변수
$+ $LAST_PAREN_MATCH 패턴 내의 가장 뒤쪽에 위치한 괄호 안의 substring을 지정하는 변수로 alternative matching 사용시 편리하다.
$* $MULTILINE_MATCHING default로 0의 값을 가지면서 single-line matching mode를 지정하고, 1의 값을 가지게 되면 multi-line matching mode를 지정한다.


여기서 제시된 여러 special variable 중에서 $*만이 값을 바꿀 수 있는 변수이고, 나머지 변수들은 모두 read-only의 속성을 가지는 변수이다.

다음은 local special variable을 사용한 예제로서, default input variable인 $_에서 pattern matching을 수행하고 match가 일어난 부분과 바로 앞부분, 바로 뒷부분이 $`, $&, $'에 저장됨을 보여준다.

 

$_ = 'abcdefghi';
/def/;
print "$`:$&:$'n";


출력결과는 abc:def:ghi 이다.

다음은 위치상으로 가장 뒤쪽에서 매치가 일어나는 부분은 Revision: 뒤쪽의 문자열이며, 이 문자열은 $+에 저장됨을 알 수 있는 예제이다. pattern matching이 성공적으로 수행되면(match가 일어나면) $rev에 revision값을 저장하게 된다.

 

/Version: (.*)|Revision: (.*)/ && ($rev = $+);


b) Per-Filehandle variable

Filehanle이란 사용자가 작성한 Perl program과 외부에 존재하는 파일사이의 I/O 연결을 위한 Perl program의 이름이다. Unix의 표준 file-descriptor를 지원하기 위한 filehandle로는 STDIN(표준입력)와 STDOUT(표준출력), STDERR(표준에러출력)가 있다. 이외에도 사용자가 특정한 파일을 다루기 위해 filehandle을 지정할 수 있다. 자세한 내용은 파일조작에 관련된 절을 참고하도록 하자.

method HANDLE EXPR 또는 HANDLE->method(EXPR)과 같은 형식으로 지정한 다음에 다음과 같은 코드를 사용하여 다음의 변수들을 지정 또는 변경할 수 있다. HANDLE위치에는 사용할 filehandle의 이름을 지정하면 되고, EXPR위치에는 현재 filehandle의 속성의 값을 지정할 수 있다. 사용가능한 method는 아래 정리되어 있다.

 

use FileHandle;
$| $OUTPUT_FLUSH_NUMBER autoflush HANDLE EXPR 값을 0이 아닌 값으로 지정하면, write또는 print문장 후에 fflush(3)함수를 호출하여 현재 선택된 output channel로 출력을 강제한다.
$% $FORMAT_PAGE_NUMBER format_page_nubmer HANDLE EXPR   현재 선택된 output channel의 현재 page 번호이다.
$= $FORMAT_LINES_PER_PAGE format_lines_per_page HANDLE EXPR 현재 선택된 output channel의 현재 page 길이(프린트 가능한 line의 수)이다.
$- $FORMAT_LINES_LEFT format_lines_left HANDLE EXPR   현재 선택된 output channel의 남아있는 line의 수이다.
$~ $FORMAT_NAME format_name HANDLE EXPR           현재 선택된 output channel의 현재 report format의 이름이다.
$~ $FORMAT_TOP_NAME format_top_name HANDLE EXPR 현재 선택된 output channel의 현재 top-of-page format의 이름이다.


다음은 관련된 특수한 변수들의 사용 예제이다.
 

use FileHandle;
use English;

print '$| = '."$|n";
print '$% = '."$%n";
print '$- = '."$-n";
print '$~ = '."$~n";
print '$^ = '."$^ n";

print '$= = '."$=n";<
print '$= = '."$FORMAT_LINES_PER_PAGEn";
format_lines_per_page STDOUT 30;
print '$= = '."$FORMAT_LINES_PER_PAGEn";
print '$= = '."$=n";


특정 filehandle인 HANDLE에 per-filehandle special variable을 지정해주는 예제는 다음과 같다.
 

select((select(HANDLE), $| = 1, $^ = 'mytop')[0]);


c) Global Special variable
 

$_ $ARG default input string, standard input이나 첫 번째 argument로 넘겨진 파일을 읽을 때 넘겨져 오는 string을 의미한다.
$. $INPUT_LINE_NUMBER $NR 마지막으로 읽힌 filehandle의 현재 input line number이다. 여러 argument로 넘겨진 파일들을 구분하지 않으므로, 다른 파일로 바뀌더라도 line number가 계속 증가하게 된다.
$/ $INPUT_RECORD_SEPARATOR $RS input record를 구분해주는 string을 의미하며 default값은 newline character이다.
$, $OUTPUT_FIELD_SEPARATOR $OFS output field를 구분해주는 string이며, print 연산자에서 사용된다. 일반적으로는 comma(,)가 separator로 사용된다.
$ $OUTPUT_RECORD_SEPARATOR $ORS output record를 구분해주는 string으로서 보통은 print 연산자가 record뒤에 newline내지는 record separator을 찍어주지 않기 때문에 필요할 경우, 지정하여야 한다.
$" $LIST_SEPARATOR list의 구분자로 사용되는 string을 지정하는 변수이다. 기본 값으로 space가 지정되어 있다.
$; $SUBSCRIPT_SEPARATOR $SUBSEP 다차원 배열을 만들기 위해 list내에서 변수들을 나열할 경우, 그 변수들이 하나의 record로 인식되어야 하는데, 그것을 위해서 list내의 각 변수들을 join하는데 사용하는 변수이다.
$^L $FORMAT_FORMFEED
format_formfeed HANDLE EXPR
print할 때, output의 format에서 formfeed로 사용될 string을 지정하는 변수로서, 기본 값은 "f"이다.
$: $FORMAT_LINE_BREAK_CHARACTERS
format_line_break_characters HANDLE EXPR
연속적인 field를 잘라야 하는 경우 그 기준이 되는 character의 집합을 정의하는 변수이다. default로 "n-", 다시 말해서 newline과 hyphen이 사용된다.
$^A $ACCUMULATOR format line을 위한 write accumulator의 현재 값을 지정하는 변수이다.
$# $OFMT Perl5에서는 사용되지 않는, 이전 버전과의 호환성을 위해 제공되는 변수로, 숫자를 출력하기 위한 output format을 지정하는 변수이다. 초기 값은 %.14g 이다.
$? $CHILD_ERROR 마지막 실행 문에서 return되는 status값이다. 상위 8비트는 child process의 exit value이고, 하위 8비트는 어떤 signal을 받았는지와 core dump가 일어났는지의 여부에 대한 정보를 포함한다.
$! $OS_ERROR $ERRNO error에 관한 정보를 포함하는 변수로서, 사용되는 문맥에 따라 error 번호 또는 error string을 보여주게 된다.
$@ $EVAL_ERROR eval 명령으로부터 발생하는 error message를 담는 변수이다. null로 값이 지정될 경우 성공적으로 실행되었음을 의미한다.
$$ $PROCESS_ID $PID 현재 script를 실행하고 있는 Perl프로그램의 process id(번호)를 지니고 있는 변수이다.
$< $REAL_USER_ID $UID 현재 process의 real user id(uid)를 지닌 변수로서, process를 실행시킨 사용자의 id를 의미한다.
$> $EFFECTIVE_USER_ID $EUID 현재 process의 effective user id(euid)를 지닌 변수로서, process의 원래 소유자의 id를 의미한다. 일반적인 process의 경우, uid와 같은 값을 가지지만, setuid bit가 켜져 있는 실행파일의 경우, uid는 실행자의 id로, euid는 파일 소유자의 것으로 지정된다.
$( $REAL_GROUP_ID $GID 현재 process의 real group id(gid)를 지정하는 변수이다.
$) $EFFECTIVE_GROUP_ID $EGID 현재 process의 effective group id(egid)를 지정하는 변수이다.

 

 

출처 : http://ttongfly.net/zbxe/?document_srl=45342&mid=scriptprogramming&listStyle=&cpage=

 

Perl 문법설명

 

 

다음의 기사는 월간 프로그램 세계 1997년 6월호 특집기사로 실렸던 것입니다. 특집기사는 총 3부로 이루어져 있는데, 1부는 Perl의 소개, 2부는 Perl의 문법, 3부는 Perl을 이용한 CGI 예제 프로그램 작성으로 구성되어 있습니다. 제가 맡은 부분은 2부였고 총 분량의 절반에 해당합니다. 1부와 3부는 김대신(웹데이타뱅크)씨가 맡으셨습니다. 다음의 글은 제가 초안으로 작성한 텍스트 파일을 HTML문서로 약간 손을 본 것입니다.

차례

 

  1. 소개

  2. Perl의 문법
    1. 변수(Variable)
      1.   
      2. 수치(number)
          
      3. 문자열(string)
          
      4. scalar variable
          
      5. vector variable
          
      6. 특수한 변수(Special variable)
          
      7. 레퍼런스(reference)
          
      8. 배열의 배열, 해시의 배열, 배열의 해시
    2. 식(Expression)
      1.   
      2. 기본 연산자
          
      3. 추가 연산자
          
      4. 기본 입출력 연산자
          
      5. 비교 연산자
    3. Control Structure(제어 구조)
      1.   
      2. if
          
      3. unless
          
      4. while/until
          
      5. for
          
      6. foreach
          
      7. do/while, do/until
          
      8. goto
          
      9. next, last, redo
    4. 서브루틴(Subroutine)
      1.   
      2. 정의와 사용
          
      3. my와 local
    5. 패턴 매칭(Pattern Matching)
      1.   
      2. 정규 표현식(regular expression)
          
      3. match, substitute, translate
          
      4. 문자열 pattern 조작

소개

펄은 임의의 텍스트 파일들을 검색하고 그 파일에서 정보를 추출하며, 그 정보에 따라 보고서를 작성하는데 최적화된 언어이다. 또한 많은 시스템 관리 작업에 좋은 언어이다. 이 언어는 실용적일 수 있도록 만들어졌기 때문에 크기가 아주 작거나 아름답게 만들어지지지 는 않았지만 사용하기 쉽고 효율적이며 완벽하다고 말할 수 있다. 펄은 C와 sed와 awk와 sh 등의 사람들이 친숙하게 생각하는 언어들의 장점을 모아서 만든 것이기 때문에 배우기 어렵지 않다. 표현식은 거의 C와 비슷하며, 다른 유닉스 유틸리티와는 달리 용량 등의 제한이 없다. 주로 text를 처리하는데 뛰어난 능력을 보여주지만, 바이너리 자료를 다루는데 있어서도 데이터베이스를 만드는 기능이 있을 정도이다. sed나 awk를 사용하는데 문제가 발생한다면 C로 짜는 대신에 펄로 작성하면 스크립트를 거의 바꾸지 않아도 된다.

2부. 펄의 문법

Perl의 저자, Larry Wall이 말했던 것처럼 Perl은 한 가지 일을 하기 위해 10가지 방법을 제시하는 언어이다. 어떻게(how) 할 것인지가 중요한 게 아니라 무엇을(what) 할 것인지를 먼저 생각하고 프로그래밍을 해야 할 것이다. 그러나 다양한 표현 방식들을 많이 익히면 익힐수록 프로그래머에게 더 많은 가능성이 열리는 셈이다. 다음의 글은 독자들이 기본적인 C프로그래밍을 이해할 수 있고 유닉스의 shell기반의 작업들에 무지하지 않음을 가정하고 쓰여진 것이다. 그러나 가능하면 초보자들도 이해할 수 있도록 쉬운 표현과 예제를 이용하였다. 다음의 설명은 Perl 5를 기준으로 쓰여졌으나, Perl 4에서도 무난하게 사용 가능할 것이다.


1. 변수(Variable)

기본적으로 Perl은 변수에 대해, C와 같이 강력한 type checking을 하지 않는다. 다시 말해서 '값이 어떤 방식으로 저장되어있는가'는 '어떻게 사용할 것인가'와는 별개의 문제라는 것이다. C프로그래밍에 익숙한 사용자라면 int c = 'x'; 으로 정의된 변수 c가 문자형으로도 정수형으로도 사용 가능한 것을 떠올릴 수 있을 것이다. 그런 것을 확장해서 생각해보면 Perl의 변수들은 여러 형태로 사용할 수 있다. 그것은 Perl 인터프리터(interpreter;해석기)가 내부적으로 자동 변환해 주기 때문에 가능한 것이다.

  1) 수치(number)

Perl에는 정수형 수치는 존재하지 않는다. 모든 수치는 double-precision floating point형 수치로 존재한다. 다음과 같은 형태의 수치는 float literal(소수형 상수)이다.


 

111.25
23.25e91
-12.5e29
-12e-34
3.2E-23


다음과 같은 형태의 수치는 integer-literal(정수형 상수)이다. 숫자 앞에 0이나 0x를 붙여쓰게 되면 각각 8진수와 16진수를 의미하게 된다.

 

342
-2423
0377
-0xf0


  2) 문자열(string)

문자열은 이름이 뜻하듯이 연속된 문자들의 순열이다. 일반적인 ASCII 문자는 128개로 표현이 되지만, Perl에서는 특수문자가 표현되어야 하기 때문에 extended ASCII를 지원하여 문자열 내부의 각각의 글자는 0에서 255까지의 ASCII값을 가지게 된다. 문자열은 여러 형태의 두 quotation mark로 감싸서 표현할 수 있는데, 대표적인 케이스는 ''(single-quote)와 ""(double-quote), ``(back-quote)이다. single-quote사이에 들어가는 문자열은 interpolation을 하지 않고, double-quote사이에 들어가는 문자열은 interpolation을 하게 되는 차이점이 있다. 그러면 interpolation이란 무엇인가 예를 보면서 이해하도록 하자.

 

$str1 = 'hellonneveryone';
$str2 = "hellonneveryone";
print $str1 . "n";
print $str2 . "n";


두 문장은 quotation mark가 다르다는 점을 제외하고는 차이점이 없다. 그런데 출력결과는 다음과 같이 다르게 된다.
 

hellonneveryone  # 이것은 str1의 출력 결과이다.
                   
hello              # 이것은 str2의 출력 결과이다.

everyone


위와 같은 escape character뿐만 아니라 이미 정의되어진 변수들을 문자열 안에서 사용하는 경우에도 interpolation의 가능 여부에 따라 그 변수가 해석되기도 하고 그렇지 않기도 한다.
 

$str0 = "I'm a boy.";
$str1 = 'hello $str0';
$str2 = "hello $str0";
print $str1 . "n";
print $str2 . "n";


결과는 다음과 같다.
 

hello $str0       # str1의 출력 결과
hello I'm a boy.  # str2의 출력 결과


single-quote 문자열에서 single-quote(')를 표현하는 방법은 backslash뒤에 single-quote를 쓰는 것이다.
 

print 'I'm a boy.';  # 출력 결과 I'm a boy.


다음은 double-quote안에서 특별한 효과를 가지는 escape character의 종류와 그 의미에 관한 표이다.
 

n newline 다음 줄로
r return 줄의 맨 앞으로
t tab 탭
f formfeed
b backspace
v vertical tab
a alarm bell
e ESC
73 octal value 8진수(여기서는 73(8) = 7*8+3(10) = 59(10))
x7f hexadecimal value 16진수(여기서는 7f(16) = 7*16+15(10) = 127(10))
cC 제어문자 C
  backslash
" double-quote
l 다음 글자를 대문자로
L 다음 글자를 소문자로
u 뒤에 오는 모든 글자를 대문자로
U 뒤에 오는 모든 글자를 소문자로
Q 뒤에 오는 모든 특수문자에(non-alphanumeric) 를 붙여서
E U, L, Q의 끝을 표시


마지막으로 back-quote가 있는데, 이것은 문자열이라기보다는 문자열을 shell에서 실행한 결과 값을 저장하게 된다. back-quote는 back-tick이라고 부르기도 한다.
 

$time_of_today = `date`;
print $time_of_today;  # 출력 결과 Mon Apr 27 20:59:04 KST 1998


위와 같은 코드에서는 Perl이 date라는 프로그램을 실행하여 나오는 값이 변수에 저장되게 된다. back-quote문자열에서는 double-quote문자열에서와 마찬가지로 interpolation이 되어진다. 다음 코드는 shell에서 "ls | grep doc"를 실행한 것과 같은 결과를 출력하는 것이다.
 

$keyword = 'doc';
print `ls | grep $keyword`;


출력결과
 

jdbcprog.doc
vi.doc
xprog.doc


다음의 표는 quotation의 여러 가지 방법에 대해 정리한 것이다.
 

관습적 사용      일반적 사용      의미   interpolation여부
''   q//   문자열상수 x
""   qq//   문자열상수 o
``   qx//   실행명령 o
()   qw//   list   x
//   m//   pattern match    o
s///   s///   substitution     o
y///   tr///   translation      x


일반적 사용에서 q 다음에 나와있는 backslash(/)는 다른 문자로 바꾸어 사용할 수 있다. 자세한 것은 뒤에 나오는 소단원을 참고하도록 하고 간단한 예제를 통해 그 사용법을 알아보도록 하자.
 

$abc = q$I'm a boy. You're a girl.$;
$def = qq#Hello,neveryone#;
$ghi = q&
            while (test != 0) {
                    i++;
                printf("%d", i);
            }
&;


변수 abc는 $를 single-quote(') 대신으로 사용하였고, def는 #을 double-quote(") 대신으로 사용하였다. ghi의 경우, multi-line string을 지정하는데, single-quote(') 대신에 &기호를 사용하였다.

  3) scalar variable

scalar variable은 하나의 값을 가지는 변수를 뜻하고 다음에서 살펴 볼 vector variable과는 상대되는 표현이다. scalar variable은 앞에서 보았던 수치나 문자열과 같은 값을 오로지 하나만 가지는 값이다. 일반적으로 scalar variable은 $기호를 변수 이름 앞에 붙여 vector variable과 구분한다. Perl에서는 C에서와 마찬가지로 변수의 이름은 대소문자가 달라지면 전혀 다른 변수로 인식된다. 다음의 변수들은 모두 다르게 구분되는 scalar 변수들이다.

 

$abc
$ABC
$account_number_of_bank1
$account_number_of_bank2
$xyz001


scalar variable에 대해서 산술 연산자 등의 일반적인 연산자를 수행할 수 있다.

  4) vector variable

vector variable은 크게 세 가지 종류로 나눌 수 있는데, array와 associative array가 그것이다. Perl에서는 array는 list라는 이름으로, associative array는 hash라는 이름으로 일컬어지기도 한다.

list는 변수 이름 앞에 @표시를 하여 구분하고, hash는 %기호를 사용한다. 다음의 변수들은 각각 list와 hash의 예이다.

 

@certain_list = ("abc", "def", "123");
@quoted_list = qw(
  1, 2, 3,     
  4, 5, 6,
  7, 8,
);
%a_special_hash = (('test', "hello"), ('verify', 123));
%list_like_hash = ("red", 0xf00, "green", 0x0f0, "blue", 0x00f);
%another_special_hash = (
  red => 0xf00,
  green => 0xf00,
  blue => 0xf00,
);


vector variable은 다른 vector 형태의 variable을 포함하여 지정할 수 있다.
 

@next_list = ("abc", "def", "123", @previous_list);
%general_hash = (%a_special_hash, %list_like_hash);


vector variable은 scalar variable과는 달리 주의해서 사용해야 한다. quotation을 하는 경우와 아닌 경우가 다르고, 그 변수를 vector차원에서 다루는 경우와 그의 원소인 scalar차원에서 다루는 경우가 다르다. 다음 예제를 참고하여 차이점을 알아보도록 하자.
 

print "@certain_list";
print @certain_list;


두 문장의 출력 결과는 다음과 같다. print는 첫 번째의 경우를 list를 quotation한 것으로 간주하여 space를 출력해주고, 두 번째의 경우를 list로 간주하여 space없이 붙여서 출력해준다.
 

abc def 123
abcdef123


다음의 hash에 관련된 코드는 list와 같을까?
 

print "%a_special_hash";
print %a_special_hash;


list와는 달리 hash의 경우 interpolation이 일어나지 않음을 알 수 있다.
 

testhelloverify123
%a_special_hash


일반적인 의미에서의 "hash"란 두개의 값을 한 쌍으로 하여 저장하는 방식을 의미하는데, 여기서도 마찬가지로 hash는 key와 value를 구분하여 사용하게 된다. 앞에서 제시한 예에서는 "test"와 "verify", "red", "green", "blue"등이 key가 되고, "hello", 123, 0xf00, 0x0f0, 0x00f등이 그 key로 찾을 수 있는 value가 된다.
 

print $a_special_hash{'test'};
$key = 'verify';
print $a_special_hash{$key};


list의 경우에는 각각의 value를 처리하기 위해 index(subscript)를 사용한다. 이런 경우에는 list 중의 하나의 scalar variable에 대한 연산이 된다. C에서의 index와는 달리 Perl에서는 ..를 이용해서 range(범위)에 대한 연산도 가능하다.
 

print $colors[0];
$id_list[3]++;
print @month[8..11];           # @month[8..11]는 @month[8, 9, 10, 11]과 같다.
$b = $namelist[$number];


list 단위의 연산도 가능하다. 대표적인 것으로 list assignment가 있다.
 

($a, $b, $c) = (3, 4, 5);
@array = ('a', 'b', 'c', 'd');


vector variable 중에는 어떤 값도 가지지 않는 변수가 존재할 수 있는데, 이런 것을 null list라고 하며 ()로 표현한다.
 

@a = ();


특히 null list는 0, "0"과 함께 조건문에서 false expression을 의미하는 것으로 사용된다.

list의 마지막 인덱스를 알기 위해서는 $#기호를 변수이름 앞에 붙이면 된다. list 중에 포함되어 있는 원소의 개수를 알기 위해서는 scalar()함수를 사용한다. 인덱스는 0부터 매겨지기 때문에 일반적으로 $#list + 1 == scalar(@list)가 성립한다.

  5) 특수한 변수(Special variable)

a) Regular expression variable

우선 $*라는 특수변수가 multi-line mode를 위해 Perl 4까지 사용되었는데, Perl 5부터는 regular expression을 사용할 때 modifier를 사용하는 방식으로 바뀌면서 더 이상 사용되지 않게 되었다. 이것은 패턴 매칭의 regular expression부분을 참고하도록 한다.

special variable들은 기억하기 쉽도록 mnemonic name을 가지고 있는데, 그러한 기능을 사용하려면 Perl 프로그램의 앞부분에서

 

use English;


로 지정해주어야 한다. 다음은 각각의 special variable과 그 역할에 대해 정리해놓은 표이다. pattern match와 관련된 변수들은 지역변수(local special variable)임을 기억하도록 하자.
 

$digit $1, $2, $3, ... 패턴 바깥에서, 매치(match)가 일어난 괄호 안의 substring을 지정할 때 사용되는 변수로 왼쪽 괄호'('의 순서대로 digit위치에 숫자가 사용된다.
digit 1, 2, 3, ... 패턴 안에서 사용되는 $digit형 변수와 같은 역할을 한다.
$& $MATCH 가장 마지막에 매치가 일어난 substring을 지정하는 변수
$` $PREMATCH $MATCH 앞쪽의 substring을 지정하는 변수
$' $POSTMATCH $MATCH 뒤쪽의 substring을 지정하는 변수
$+ $LAST_PAREN_MATCH 패턴 내의 가장 뒤쪽에 위치한 괄호 안의 substring을 지정하는 변수로 alternative matching 사용시 편리하다.
$* $MULTILINE_MATCHING default로 0의 값을 가지면서 single-line matching mode를 지정하고, 1의 값을 가지게 되면 multi-line matching mode를 지정한다.


여기서 제시된 여러 special variable 중에서 $*만이 값을 바꿀 수 있는 변수이고, 나머지 변수들은 모두 read-only의 속성을 가지는 변수이다.

다음은 local special variable을 사용한 예제로서, default input variable인 $_에서 pattern matching을 수행하고 match가 일어난 부분과 바로 앞부분, 바로 뒷부분이 $`, $&, $'에 저장됨을 보여준다.

 

$_ = 'abcdefghi';
/def/;
print "$`:$&:$'n";


출력결과는 abc:def:ghi 이다.

다음은 위치상으로 가장 뒤쪽에서 매치가 일어나는 부분은 Revision: 뒤쪽의 문자열이며, 이 문자열은 $+에 저장됨을 알 수 있는 예제이다. pattern matching이 성공적으로 수행되면(match가 일어나면) $rev에 revision값을 저장하게 된다.

 

/Version: (.*)|Revision: (.*)/ && ($rev = $+);


b) Per-Filehandle variable

Filehanle이란 사용자가 작성한 Perl program과 외부에 존재하는 파일사이의 I/O 연결을 위한 Perl program의 이름이다. Unix의 표준 file-descriptor를 지원하기 위한 filehandle로는 STDIN(표준입력)와 STDOUT(표준출력), STDERR(표준에러출력)가 있다. 이외에도 사용자가 특정한 파일을 다루기 위해 filehandle을 지정할 수 있다. 자세한 내용은 파일조작에 관련된 절을 참고하도록 하자.

method HANDLE EXPR 또는 HANDLE->method(EXPR)과 같은 형식으로 지정한 다음에 다음과 같은 코드를 사용하여 다음의 변수들을 지정 또는 변경할 수 있다. HANDLE위치에는 사용할 filehandle의 이름을 지정하면 되고, EXPR위치에는 현재 filehandle의 속성의 값을 지정할 수 있다. 사용가능한 method는 아래 정리되어 있다.

 

use FileHandle;
$| $OUTPUT_FLUSH_NUMBER autoflush HANDLE EXPR 값을 0이 아닌 값으로 지정하면, write또는 print문장 후에 fflush(3)함수를 호출하여 현재 선택된 output channel로 출력을 강제한다.
$% $FORMAT_PAGE_NUMBER format_page_nubmer HANDLE EXPR   현재 선택된 output channel의 현재 page 번호이다.
$= $FORMAT_LINES_PER_PAGE format_lines_per_page HANDLE EXPR 현재 선택된 output channel의 현재 page 길이(프린트 가능한 line의 수)이다.
$- $FORMAT_LINES_LEFT format_lines_left HANDLE EXPR   현재 선택된 output channel의 남아있는 line의 수이다.
$~ $FORMAT_NAME format_name HANDLE EXPR           현재 선택된 output channel의 현재 report format의 이름이다.
$~ $FORMAT_TOP_NAME format_top_name HANDLE EXPR 현재 선택된 output channel의 현재 top-of-page format의 이름이다.


다음은 관련된 특수한 변수들의 사용 예제이다.
 

use FileHandle;
use English;

print '$| = '."$|n";
print '$% = '."$%n";
print '$- = '."$-n";
print '$~ = '."$~n";
print '$^ = '."$^ n";

print '$= = '."$=n";<
print '$= = '."$FORMAT_LINES_PER_PAGEn";
format_lines_per_page STDOUT 30;
print '$= = '."$FORMAT_LINES_PER_PAGEn";
print '$= = '."$=n";


특정 filehandle인 HANDLE에 per-filehandle special variable을 지정해주는 예제는 다음과 같다.
 

select((select(HANDLE), $| = 1, $^ = 'mytop')[0]);


c) Global Special variable
 

$_ $ARG default input string, standard input이나 첫 번째 argument로 넘겨진 파일을 읽을 때 넘겨져 오는 string을 의미한다.
$. $INPUT_LINE_NUMBER $NR 마지막으로 읽힌 filehandle의 현재 input line number이다. 여러 argument로 넘겨진 파일들을 구분하지 않으므로, 다른 파일로 바뀌더라도 line number가 계속 증가하게 된다.
$/ $INPUT_RECORD_SEPARATOR $RS input record를 구분해주는 string을 의미하며 default값은 newline character이다.
$, $OUTPUT_FIELD_SEPARATOR $OFS output field를 구분해주는 string이며, print 연산자에서 사용된다. 일반적으로는 comma(,)가 separator로 사용된다.
$ $OUTPUT_RECORD_SEPARATOR $ORS output record를 구분해주는 string으로서 보통은 print 연산자가 record뒤에 newline내지는 record separator을 찍어주지 않기 때문에 필요할 경우, 지정하여야 한다.
$" $LIST_SEPARATOR list의 구분자로 사용되는 string을 지정하는 변수이다. 기본 값으로 space가 지정되어 있다.
$; $SUBSCRIPT_SEPARATOR $SUBSEP 다차원 배열을 만들기 위해 list내에서 변수들을 나열할 경우, 그 변수들이 하나의 record로 인식되어야 하는데, 그것을 위해서 list내의 각 변수들을 join하는데 사용하는 변수이다.
$^L $FORMAT_FORMFEED
format_formfeed HANDLE EXPR
print할 때, output의 format에서 formfeed로 사용될 string을 지정하는 변수로서, 기본 값은 "f"이다.
$: $FORMAT_LINE_BREAK_CHARACTERS
format_line_break_characters HANDLE EXPR
연속적인 field를 잘라야 하는 경우 그 기준이 되는 character의 집합을 정의하는 변수이다. default로 "n-", 다시 말해서 newline과 hyphen이 사용된다.
$^A $ACCUMULATOR format line을 위한 write accumulator의 현재 값을 지정하는 변수이다.
$# $OFMT Perl5에서는 사용되지 않는, 이전 버전과의 호환성을 위해 제공되는 변수로, 숫자를 출력하기 위한 output format을 지정하는 변수이다. 초기 값은 %.14g 이다.
$? $CHILD_ERROR 마지막 실행 문에서 return되는 status값이다. 상위 8비트는 child process의 exit value이고, 하위 8비트는 어떤 signal을 받았는지와 core dump가 일어났는지의 여부에 대한 정보를 포함한다.
$! $OS_ERROR $ERRNO error에 관한 정보를 포함하는 변수로서, 사용되는 문맥에 따라 error 번호 또는 error string을 보여주게 된다.
$@ $EVAL_ERROR eval 명령으로부터 발생하는 error message를 담는 변수이다. null로 값이 지정될 경우 성공적으로 실행되었음을 의미한다.
$$ $PROCESS_ID $PID 현재 script를 실행하고 있는 Perl프로그램의 process id(번호)를 지니고 있는 변수이다.
$< $REAL_USER_ID $UID 현재 process의 real user id(uid)를 지닌 변수로서, process를 실행시킨 사용자의 id를 의미한다.
$> $EFFECTIVE_USER_ID $EUID 현재 process의 effective user id(euid)를 지닌 변수로서, process의 원래 소유자의 id를 의미한다. 일반적인 process의 경우, uid와 같은 값을 가지지만, setuid bit가 켜져 있는 실행파일의 경우, uid는 실행자의 id로, euid는 파일 소유자의 것으로 지정된다.
$( $REAL_GROUP_ID $GID 현재 process의 real group id(gid)를 지정하는 변수이다.
$) $EFFECTIVE_GROUP_ID $EGID 현재 process의 effective group id(egid)를 지정하는 변수이다.
$0 $PROGRAM_NAME 현재 실행중인 Perl script의 이름을 지정하는 변수이다.
$[   배열의 첫 번째 원소의 index, 또는 substring의 첫 번째 글자의 index를 지정하는 변수이다. 기본적으로는 0번 원소부터 배열이 시작하지만, 1번 원소부터 배열이 시작하도록 1로 값을 바꿀 수 있다.
$] $PERL_VERSION Perl의 version과 patch level을 알려주는 변수로서, 5.004는 5번째 version에 4번째 patch level임을 의미한다.
$^D $DEBUGGING debugging flag(-D switch)가 켜져 있는지에 관한 정보를 담고 있는 변수이다.
$^F $SYSTEM_FD_MAX 현재 open되어 사용되고 있는 file descriptor의 최대 번호를 지정하는 변수이다. 보통 프로그램이 시작하게 되면 자동으로 0, 1, 2번이 STDIN, STDOUT, STDERR로 설정된다.
$^H   Perl compiler의 내부 컴파일 힌트에 관한 정보를 담는 변수이다.
$^I $INPLACE_EDIT inplace-edit extension의 값을 저장하는 변수이다. 이 값은 -i switch에 의해 지정된다.
$^O $OSNAME 현재 사용되고 있는 Operating System의 이름을 저장하는 변수이다.
$^P $PERLDB Perl debugger가 자신을 debug하지 않도록 꺼주는 내부 flag 변수이다.
$^T $BASETIME script가 실행되기 시작한 시각을 지정하는 변수이다. Unix system에서는 70년 1월 1일 0시 0분 0초(epoch)로부터의, 초단위 시간이다.
$^W $WARNING -w switch에 의해 지정되는 warning(경고) 여부의 값을 저장하는 변수이다.
$^X $EXECUTABLE_NAME Perl 바이너리가 실행 시에 가지게 되는 이름을 지정하는 변수이다.
$ARGV   argument로 넘겨져 들어온 파일의 이름이다.


다음의 예제는 동일한 의미를 가지는 코드이다.
 

$foo{$a, $b, $c}
$foo{join($;, $a, $b, $c)}


d) Global special array
 

@ARGV 넘겨져 들어온 command-line argument의 list를 저장하는 변수이다.
@INC do, require, use등의 operator를 사용할 때 필요한 Perl script를 찾는 디렉토리를 지정하는 변수이다. -I switch를 사용하여 지정된다. lib module을 사용하여도 지정 가능하다.
@F -a switch를 사용한 경우에, input line을 분리해 넣어줄 변수의 array를 지정하는 list 변수이다.
%INC module로 사용될 Perl script의 이름과 그 script의 절대경로를 저장해놓은 hash 변수이다.
%ENV shell에서 넘겨져 온 hash type의 환경변수이다. 환경변수의 이름과 그 값을 hash해 놓았다.
%SIG signal과 그에 해당하는 signal handler를 지정하는 hash 변수이다.


다음은 환경 변수를 지정하는 예제이다.
 

$ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin";


signal handler를 사용하는 예제를 참고하도록 하라. Ctrl-C를 눌러 interrupt를 걸게 되면 프로그램이 중단되게 되는데 INT signal을 가로채서 특정한 함수(signal handler)를 실행시키도록 할 수 있다.
 

sub sighandler {
  local($sig) = @_;
  print "Closing log file...n";
  close(LOG);
  exit(0);
}
$SIG{'INT'} = 'handler';


e) Global special Filehandles
 

ARGV @ARGV에서 저장된 argument로 넘겨진 file들을 다루는 filehandle이다. 는 <>로 줄여서 사용 가능하다.
STDERR standard error에 대한 filehandle이다.
STDIN standard input에 대한 filehandle이다.
STDOUT standard output에 대한 filehandle이다.
DATA Perl script에서 __END__라는 token뒤쪽에 나오는 모든 자료에 대한 filehandle이다.
_(underline) 마지막으로 다루었던 파일에 대한 정보를 cache로 저장하고 있는 filehandle이다.


  6) 레퍼런스(reference)

'레퍼런스'란 우리말로 옮기자면 '참조'라고 할 수 있다. 어떤 변수가 존재하고 그 이름을 저장함으로써 원래의 변수를 '참조'하는 다른 변수가 존재한다면 그 변수를 symbolic reference라고 한다. 반면에 hard reference라는 것도 있는데, 이것은 이름을 통해서가 아니라 실제의 값을 통해서 참조하게 된다. 여기에서는 hard reference에 더 중점을 두어 자세히 설명하려고 한다.

reference와 관련된 용어들에 대해서 잠깐 설명을 하고 넘어가자. reference를 만드는 것을 referece한다고 하면, 반대의 과정, 즉 참조 대상이 되는 변수나 상수의 값을 꺼내오는 것을 dereference한다고 한다. reference의 대상이 되는 것을 thingy(referent)라고 부른다. Perl의 저자인 Larry Wall이 thingy라는 표현을 고집하므로 여기서도 thingy라는 표현을 사용하도록 하겠다.

a) hard reference

hard reference가 가리키는 대상을 Perl에서는 흔히 thingy라고 지칭하는데, 이 thingy에 따라, hard reference를 만드는 방법은 조금씩 달라진다. 대상은 어떤 값이라도 가능한데, 여기서는 이름 있는 변수(named variable)와 서브루틴(named subroutine), 이름 없는 배열(anonymous array), 이름 없는 hash(anonymous hash), 이름 없는 서브루틴(anonymous subroutine), 파일핸들(filehandle)에 대해서 살펴보기로 하자.

우선 대개의 변수와 서브루틴은 이름을 가진다. 그러므로 이러한 일반적인 변수나 서브루틴에 대한 reference가 많이 필요하게 되며, hard reference는 (backslash)연산자를 사용함으로써 만들 수 있다.

 

$scalarref = $foo;  # $foo는 일반변수, 는 reference하는 연산자
$constref = 3.24;  # hard reference는 값에 대한 reference이다.
$arrayref = @array1; 
$hashref = %hash2; 
$globref = *STDOUT;  # *는 typeglob이며, 모든 타입을 가리킨다.
$subref = &subroutine3; 


간단히 일반화해보면, 어떤 형태의 변수나 상수에 대해서 그 앞에 연산자를 붙여주면 hard reference가 되는 것이다. reference를 통해서 그 값을 사용하기 위해서는 $, &, @, % 연산자 중의 하나를 reference변수 앞에 붙여주면 된다. reference는 그 대상(thingy)가 어떤 타입인지를 신경 쓰지 않기 때문에, 사용자가 타입 캐스팅을 하듯이 타입연산자인 $, %, &, @ 등의 연산자를 지정하는 것이 필수적이다.
 

print $$scalarref;  # print $foo;와 동일하다.
$$constref   # 3.24와 동일하다.
$$hashref{'key1'}   # $hash2{'key1'}과 동일하다.
&$subref;   # subroutine3를 호출하게 된다.
shift(@$arrayref);  # @array1에 대해 shift연산을 하는 것과 같다.


reference변수를 다시 reference할 수 있는데, 이럴 때에는 필요한 만큼 연산을 붙여 줄 수 있고, 값을 꺼낼 때에는 타입연산자의 수가 연산자의 수보다 하나 더 많은가를 확인해야 한다.
 

$multiref = 123;  # 123에 대해 연산을 4번 시행
print $$$$$multiref;  # $multiref에 대해서 $연산을 4번 시행


이번에는 이름 없는 배열과 해시와 서브루틴을 참조하는 hard reference를 다루는 법에 대해서 알아보도록 하자. 여기서 이름이 없다는 표현은, 이미 만들어져서 이름을 가지고 있는 변수나 상수의 값을 참조하는 게 아니라 reference를 만들면서 그것이 참조하는 thingy를 만들기 때문에 이름을 지어주지 못했다는 의미이다.
 

$arrayref = [1, 2, [3, 4, 5]];  # anonymous array reference
$hashref = {
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
};


$subref = sub { 
  print "When Harry met Sallyn"; # anonymous subroutine reference
};



위의 예제를 살펴보면, reference는 보이지 않고, 보통 variable에 값을 대입해 준 것처럼 보인다. 그러나 실제 assignment는 다음과 같다. 잘 비교해보도록 하자. 연산자로 사용되는 기호들이 약간씩 다르다는 것을 알게 될 것이다.
 

@array = (1, 2, (3, 4, 5));
%hash = (
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
);
&subroutine1;
sub subroutine1 {
  print "Sleepless in Seattlen"; # anonymous subroutine reference
};


두 예제를 비교해 본 바와 같이, anonymous array reference는 [ ]을, anonymous hash reference는 { }를, anonymous subroutine reference는 sub { }를 연산자로 사용한다는 것을 알 수 있다.

b) hard reference in nested data structure

$연산자로 dereference하는 것 이외에도, ->연산자(arrow operator)를 사용해서 array나 hash의 값을 dereference하는 방법도 있는데, 이러한 방법들은 '배열의 배열'을 구현할 때 긴요하게 쓰인다. 다음은 같은 효과를 내는 연산자 사용에 대한 예이다.

 

$$arrayref[0] = "first";
${$arrayref}[0] = "first";
$arrayref->[0] = "first";

$$hashref{'key2'} = "McLean";
${$hashref}{'key2'} = "McLean";
$hashref->{'key2'} = "McLean";


->연산자는 dereference의 기능을 $연산자보다 더 직관적으로 제시하기 때문에 C프로그래밍에 익숙한 사용자에게 유용할 것이다. 다음은 ->연산자를 이용한 1차원 배열의 원소를 dereference하고, '배열의 배열'내의 원소를 dereference하는 방법을 보인 예이다.
 

$arrayref->[3] = "list-item1";

$arrayref->[3]->[4] = "multi-dimensional-item2";
$arrayref->[3][4] = "multi-dimensional-item2";
$$arrayref[3][4] = "multi-dimensional-item2";


C프로그래머에게는 '배열의 배열'을 나타내는 위의 표현 중에서 마지막 것이 친숙해 보일 수 있으나, Perl에서는 []연산자가 우선 순위(precedence)가 낮아서 reference가 어떻게 사용되고 있는지를 알아보기가 어렵다는 이유로 권하지 않는 방법이다. 그 위의 두 가지 방법을 이용하여 다중 배열을 나타내기로 한다.
 

$ref_list_of_list = [
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
];
print $ref_list_of_list[0][2];      # terminator가 출력된다.
print $ref_list_of_list->[2][1];    # electronics가 출력된다.
print $ref_list_of_list->[1]->[3];  # signed가 출력된다.


만약 for loop를 사용해서 모든 원소를 출력하기를 원한다면, 각 sub list가 가지고 있는 원소의 개수를 알아야 하는데, length()함수를 써서 원소의 개수를 구해 내거나, $#연산자를 사용하여 리스트변수의 마지막 인덱스를 얻을 수 있다.

b) symbolic reference

symbolic reference는 reference가 가리키고 있는(여기서는 thingy가 아님을 유의할 것) 변수의 이름을 문자열로 해서 저장하게 된다. 다시 말해서 변수의 이름을 가진다는 것은 symbolic reference를 만드는 것이다. hard reference가 thingy를 직접 참고하는 것에 반해서 symbolic reference는 변수의 이름을 통해서 그 값에 접근하게 된다. 그러므로 항상 named variable에 대해서만 symbolic reference를 만들 수 있는 것이다.

symbolic reference를 만드는 것은 단순히 변수의 이름을 지정하기만 하면 되며, 그 사용법도 hard reference와 다르지 않다. 타입연산자를 앞에 붙여주면 그 값을 취할 수 있게 된다.

 

$var1 = "test";
$sr = "var1";
$$sr = "verify"; # $var1 eq "verify"

@var2 = ("hello", "program", "world");
$sr = "var2";
push(@$sr, "perl"); # @var2 eq ('hello', 'program', 'world', 'perl')


  7) 배열의 배열, 해시의 배열, 배열의 해시

배열의 배열은 사실상 Perl에서 제공하려고 의도하는 것은 아니다. Perl은 단순히 1차원의 배열만을 제공하는데, C와는 달리 scalar값이 놓일 위치에 vector형 변수가 놓일 수 있으므로 자연스럽게 배열의 배열, 해시의 배열, 배열의 해시 등과 같은 복합적인 data structure를 만들 수 있다.

a) 배열의 배열

다음과 같은 코드를 실행시켜 보자. 아마 아무 출력도 없을 것이다. 그 이유는 Perl이 1차원 배열만을 제공하기 때문에 $list_of_list[0][2]와 같은 형식은 무시되기 때문이다.(-w 스위치를 사용하면 warning을 볼 수 있다.)

 

@list_of_list = (
  ("separator", "delimiter", "terminator"),
  ("long", "short", "int", "signed", "unsigned"),
  ("physics", "chemistry", "computer"),
);


print $list_of_list[0][2]; 
print $list_of_list[2][1]; 
print $list_of_list[1][3];


2차원 배열을 구현하기 위해서는 reference를 이용해야 한다.
 

@list_of_list = (
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
);
print $list_of_list[0][2];  # terminator가 출력된다.
print $list_of_list[2][1];  # electronics가 출력된다.
print $list_of_list[1][3];  # signed가 출력된다.


b) 배열의 해시

리스트를 해시 값으로 사용하여 해시를 만드는 것도 비슷한 방법에 의해 가능하다.

 

%hash_of_list = (
  token => ["separator", "delimiter", "terminator"],
  type => ["long", "short", "int", "signed", "unsigned"],
  science => ["physics", "chemistry", "computer"],
);

print $hash_of_list{'token'}->[1]; # delimiter가 출력된다.
print $hash_of_list{'type'}[0];    # long이 출력된다.
print $hash_of_list{science};      # ARRAY(0xb2074)같은 정보가 출력된다.
print $hash_of_list{science}->[2]; # computer이 출력된다.
print @$hash_of_list{science};     # 아무 것도 출력되지 않는다.
print @{$hash_of_list{science}};   # physicschemistrycomputer 출력


c) 해시의 해시
 

%hash_of_hash = (
  token => {
    s => "separator", 
    d => "delimiter",
    t => "terminator"
  },
  type => {
    l => "long",
    s => "short",
    i => "int"
  },
  science => {
    e => "chemistry", 
    c => "computer",
  },
);

print $hash_of_hash{token}->{s}; # separator 출력
print $hash_of_hash{type}{i};    # int 출력
print $hash_of_hash{science};    # HASH(0xb205c)같은 정보가 출력된다.


다만 주의할 것은 해시나 리스트는 해시의 키(key)로 사용할 수 없다는 것이다. 이유는 key는 단순한 문자열로 취급이 되기 때문이다. 리스트나 해시를 넣는다고 해도 문자열 이상의 의미를 가지지는 못하게 된다.

2. 식(Expression)

  1) 기본 연산자

a) 수치 연산자

Perl은 수치에 대해서 사칙연산을 기본적으로 제공한다. +, -, *, /가 그에 해당하는 연산자이다. 그리고 FORTRAN과 같이 **에 의한 거듭제곱 연산도 가능하다. 나머지를 구하는 연산도 있는데, %를 연산자(operator)로 사용하며, 피연산자(operand) 모두를 정수로 취급한다. 반면에 나누기 연산자인 /는 피연산자 모두를 실수로 취급한다. 논리연산자인 <, <=, ==, >=, >, !도 사용 가능하다.

다음은 수치 연산자의 사용 예이다.
 

2 + 3  # 5
5.1 - 2.4 # 2.7
3 * 12  # 36
14 / 2  # 7
10.2 / 0.3 # 34
10 / 3  # 3.33333...

if (3 > 4) {
  print "3 is greater than 4.n";
} else {
  print "3 is not greater than 4.n";  # 비교문이 거짓이므로 여기가 실행됨
}


b) 문자열 연산자

문자열 연산자에는 C에서는 볼 수 없는 연산자들이 많이 등장한다. 우선은 문자열들을 붙이는 연산자인 .(dot)이 있고, 문자열을 정수번 반복해서 붙여주는 x연산자도 있다. 다음의 예제를 참고하도록 하자.
 

$b = "Hello, ";
$c = "world";
$a = $b . $c;  # $a = "Hello, world"

$a = "boy";
$b = $a x 3;  # $b = "boyboyboy"
$c = $a x 4.2;  # $b = "boyboyboyboy", 4.2는 4로 cast된다.


c) 대입연산자(assignment operator)

대입연산자에는 C와 마찬가지로 =이 기본적인 연산자이다. 이밖에도 C에서 사용하는 대입연산자들은 거의 Perl에서 채택되어져 있다. +=, -=, *=, /=, &=, |=. ^=, %=가 그 예이다. 그 밖에도 .=, x=, ||=, **=, <<=, >>=의 연산자들이 있다. 이와 같은 대입연산자들은 %연산, .연산, x연산, ||연산을 수행한 후에 그 결과를 대입하는 것이므로 보충 설명이 없어도 이해에 어려움이 없을 것이다.
 

$a *= 3;  # $a = $a * 3;
$b .= "n";  # $b = $b . "n"
$c ||= 2;  # $c = $c || 2, $c가 2가 아니면 2의 값을 대입한다.


d) 연산자 우선 순위와 결합법칙

여러 연산자들의 결합순위와 우선 순위를 다음의 표로 정리해놓았다. 위쪽에 있는 연산자일수록 아래쪽 연산자들보다 우선 순위가 높다. 같은 줄에 있는 연산자들은 같은 우선 순위 가지게 되고 결합순위에 따라 연산의 순서가 정해진다.
 

결합순위 연산자
없음 ++ --
! ~ -(단항연산)
**
=~ !~
* / % x
+ -(이항연산) .
<< >>
없음 file test operator
없음 named unary operator
없음 < <= > >= lt le gt ge
없음 == != <=> eq ne cmp
&
| ^
&&
||
없음 ..
?:(삼항연산)
대입 연산자 (+= -= 등)
,
없음 list 연산자


e) 수치와 문자열 상호변환

Perl은 수치와 문자열, 정수와 실수 사이의 변환을 자동으로 해준다. 수치 앞 뒤쪽에 오는 쓸데없는 문자들을 자동으로 제거해주므로 다음과 같은 연산이 가능하다.
 

$a = "   3.5abcd" * 4;
print $a;   # 3.5 * 4 = 14가 출력된다.
$b = "3" + "4";   # $b = 7


Perl이 자동으로 변환해 주는 것은 문자열 또는 수치가 이중적인 의미를 가질 때, 앞쪽이나 뒤쪽에 위치하는 연산자가 필요로 하는 피연산자가 수치인가 문자열인가를 결정할 수 있기 때문이다.
 

print "boy" . (3 * 2);  # boy6가 출력된다.
print "boy" x (3 * 2);  # boyboyboyboyboyboy가 출력된다.


괄호 안의 3 * 2이 먼저 수치로서 계산이 된다. 수치로 인식되는 이유는 *이 수치를 피연산자로 가지기 때문이다. 다음에는 문자열을 결합시켜주는 . 연산자를 만나게 되므로 (3 * 2)의 결과인 6을 문자열로 변환시켜서 인식하게 된다. 이러한 방식으로 자동변환이 일어나게 되므로 프로그래머는 사소한 것에 신경 쓰지 않아도 된다.

  2) 추가 연산자

또 하나 프로그래머가 매달릴 필요가 없는 것은 연산자를 연산자로 볼 것인가 함수로 볼 것인가의 문제인데, Perl에서 제공되는 대개의 연산자는 연산자이면서 함수로 볼 수 있기 때문에 C처럼 ()를 반드시 써 줄 필요가 없다.

a) scalar operator
 

rand $a 0과 $a 사이의 임의의 값(random number)을 반환한다. 0이상 $a미만의 범위의 소수를 구하게 된다.
srand $a random number를 만들어 낼 때 사용하는 seed값을 지정한다. srand(time^$$)처럼 현재시간을 알려주는 time연산자와 현재 프로세스의 번호를 지정하는 $$변수를 넣어서 사용하기도 한다.
substr $a, $b, $c $a라는 문자열에서 $b의 offset위치에 $c개만큼의 원소를 지정하게 된다. substr을 이용해서 $a에 새로운 값을 넣어주거나 $a에서 원소를 꺼내올 수 있다. $c부분은 생략 가능하다.
index $a, $b, $c 문자열 $a에서 $b가 나타나는 위치(offset)을 알려준다. $c부분은 찾기 시작하는 위치를 지정하는 것인데, 생략되면 0의 값이 대신 사용된다.
chop $a chop은 $a의 마지막 글자를 제거하는 연산자이며 Perl 5에서는 다음의 chomp을 권장한다. $a는 리스트라도 처리할 수 있다.
chomp $a chomp는 chop의 안전한 버전이며, $a의 마지막 글자가 $/변수($INPUT_RECORD_SEPARATOR, $RS)의 값을 가지면 제거하는 역할을 한다. 대개는 입력에 붙어서 들어오는 newline character를 제거할 때 사용한다.


b) vector operator
 

shift @a 리스트 @a의 가장 앞쪽에 있는 원소를 꺼내준다.
unshift @a, $b $b를 @a의 가장 앞쪽에 쑤셔 넣어 준다.
pop @a @a의 가장 뒤쪽에 있는 원소를 꺼내준다.
push(@a, $b) @a의 가장 뒤쪽에 $b를 추가해준다.
splice @a, $b, $c, @d; @a의 offset이 $b되는 곳에서 $c개의 원소를 지정할 때 사용한다. @d가 사용되는 경우에는 @d를 $c개의 원소와 바꾸어준다. @d가 생략되면 $c개의 원소를 반환한다.
keys %a 해시 변수 %a의 key를 모아서 리스트 형태로 반환한다.
$a .. $b ..은 범위연산자(range operator)라고 하는데, $a에서 $b까지의 값을 리스트 형태로 반환한다. $a와 $b에 들어갈 수 있는 값은 정수나 문자이다. 문자열을 사용하면 그 사이에 존재할 수 있는 모든 문자열 조합을 만들어 주기도 하는데, 시스템의 자원을 낭비하기 쉬우므로 조심해야 한다.
, comma(,) 연산자는 리스트에서 separator로 사용되는 comma와는 다른 의미를 가진다. comma 연산자는 ,뒤쪽의 값을 반환한다. ,로 여러 개의 값이 나열되면 마지막 값이 리턴 된다.
sort @a 리스트변수 @a를 정렬해준다. sort의 기준을 제시하는 비교함수나 블럭을 지정할 수도 있는데, 리스트 앞에 지정해준다. 이 때 비교함수나 블럭에서는 <=>, cmp 연산자와 논리연산자등을 사용하여 +1, -1, 0등의 값을 반환하도록 한다.
reverse @a 리스트의 원소의 순서를 반대 방향으로 바꾸어준다.
grep PATTERN, @a
grep FILETEST, @a
리스트변수 @a를 읽어들여 패턴매치나 파일 테스트를 해서 성공할 경우, 그 리스트의 원소인 line이나 string을 반환한다.
join $b, @a @a의 원소들을 $b를 delimiter로 하여 묶어 하나의 문자열로 반환한다.
split PATTERN, $a, $b 문자열 $a를 PATTERN에 나오는 character를 delimiter로 해서 나누어 리스트형태로 반환한다. $b를 사용하게 되면 그 값에 해당하는 개수까지 원소들을 생성해준다.


c) file test operator

다음은 파일에 대한 조건식을 만드는 operator을 정리한 표이다. 다음의 테스트는 참/거짓의 값을 가지거나 특정한 결과 값을 return해 준다.
 

-r 파일을 읽을 수(readable) 있는가?
-w 파일을 쓸 수(writable) 있는가?
-x 파일을 실행시킬 수(executable) 있는가?
-o 파일이 $euid의 사용자 소유인가?
-R 파일이 $uid의 사용자에 의해 읽혀질 수 있는가?
-W 파일이 $uid의 사용자에 의해 쓰여질 수 있는가?
-X 파일이 $uid의 사용자에 의해 실행가능한가?
-O 파일이 $uid의 사용자 소유인가?
-e 파일이 존재하는가?
-z 파일의 크기가 0인가?
-s 파일의 크기(size)
-f 파일이 정규파일(디렉토리가 아닌)인가?
-d 파일이 디렉토리인가?
-l 파일이 symbolic link인가?
-p 파일이 FIFO와 같은 named pipe인가?
-S 파일이 socket인가?
-b 파일이 block special file인가?
-c 파일이 character special file인가?
-t filehandle이 tty(terminal)에 열려 있는가?
-u setuid bit이 켜져 있는 파일인가?
-g setgid bit이 켜져 있는 파일인가?
-k sticky bit이 켜져 있는 파일인가?
-T 파일이 텍스트(text) 파일인가?
-B 이진(binary) 파일인가?
-M file의 최종 수정 시간(modification time, mtime)
-A file의 최종 접근 시간(last access time, atime)
-C file의 최종 변경 시간(inode change time, ctime)


다음은 file test를 이용한 조건식의 예이다.
 

while (<>) {
  chomp;   # default input string의 마지막 n을 제거한다.
  next unless -f $_;  # 정규파일이 아닌 경우에는 다음으로 넘어간다.
}

stat($file);
print "Readablen" if -r _; # _는 마지막으로 사용된 filehandle이다.
print "Writablen" if -w _; # readable, writable, executable한지 체크한다.
print "Executablen" if -x _;

&newfile if -M $file < 5; # mtime이 5일 이내라면 서브루틴을 호출한다.


  3) 기본 입출력 연산자

입출력이란 프로그램이 자료를 외부세계에서 넘겨받고 그 자료를 처리한 결과를 외부세계에 넘겨주는 과정을 의미한다. Perl에서 가능한 방법은 파일을 이용한 것이고, 프로그래머는 filehandle이라는 것을 가지고 파일을 다룰 수 있게 된다. 파일을 열어서 filehandle을 지정하는 것은 open함수를 사용하면 되고, 더 이상 사용하지 않게 된 파일을 닫고 filehandle의 사용을 포기하는 것은 close함수를 이용하면 된다.

그러나 입출력 과정에 filehandle을 매번 사용한다는 것은 프로그램 작성에 상당한 불편을 안겨줄 것이다. 그리하여 Perl에서는 Unix시스템과 마찬가지로 표준입력(STDIN), 표준출력(STDOUT), 표준에러(STDERR)를 제공한다. 표준입력이란 키보드를 통해 자료를 입력받거나, 다른 프로그램에서 파이프나 redirection을 통해 자료를 넘겨받는 것이다. 반면에 표준출력은 print 연산이나 printf를 통해서 화면으로 결과를 출력하는 것이고, 표준에러는 화면에 에러메시지를 보여주는 것이다.

a) 입력

일반적으로 키보드로부터의 입력은
 

$input = ;
@input = ;


과 같은 형태로 받아들일 수 있다. $input이나 @input에는 사용자가 키보드를 통해 눌렀던 모든 키 입력이 문자열 또는 리스트의 형태로 저장된다.

Perl에서 즐겨 사용되는 입력방식에는 다음과 같은 것들이 있다. 짧은 코드에서 긴 코드까지 모두 같은 효과를 가지며, 문맥적으로 같은 의미를 가진다.
 

print while 
print $_ while ;
print $_ while definded($_ = );
for (;;) { print; }
for (;;) { print $_; }
while () { print; }
while () { print $_; }
while (defined($_ = )) { print $_ };


$_는 default input string을 저장하는 변수로서 대개의 연산자에서 생략 가능하다. 거꾸로 말해서, 연산자만 나오는 경우는 대개 $_를 염두에 둔 것이라고 볼 수 있다. 에서 들어온 모든 입력은 $_에 자동으로 저장된다. $_대신에 다른 변수를 사용해도 별로 상관은 없으나, 생략해서 사용할 수는 없다.

STDIN같은 표준입출력에 관련된 filehandle은 굳이 open의 과정이 필요 없으나, 일반적인 파일에 대한 filehandle은 open의 과정이 명시되어야 한다.

 

 

 

open(FILE, "test.c");
$_ = ;
print;

이 예제는 test.c라는 파일을 FILE이라는 filehandle을 통해서 다루게 되고 default input string에 한 줄 입력을 받아서 그것을 다시 출력해주는 작업을 하게 된다. 그러나 대개는 한 줄만 입력을 받는 게 아니라 파일 전체에 대해서 여러 줄의 입력을 받아야 하므로 loop안에서 사용하거나 리스트에 저장했다가 shift연산자를 사용하여 꺼내어 사용할 수 있다. 그러나 리스트에 파일의 큰 내용이 저장되는 것은 시스템에 부하를 주게 되므로 loop를 사용하는 방법을 익히도록 하자.

 

 

 

while ($input = ) {
  print "/* $input */n";
}

이 예제는 FILE을 통해 $input에 입력을 받고 그 line을 comment기호로 감싸는 작업을 수행하는 것이다.

Perl 프로그램이 filter로 사용되는 게 아니라면 대개는 프로그램의 argument로 파일 이름을 넘겨받아 사용하게 되는데, 이것은 아주 간단하다. 다음은 argument로 넘겨진 모든 파일을 열어서 한 줄씩 입력을 받아서 출력하는 예이다.

 

 

 

while (<>) {
  print;
}

이 코드는 다음과 동일한 의미를 가진다.

 

 

 

@ARGV = ('-') unless @ARGV;
while ($ARGV = shift) {
  open(ARGV, $ARGV) or warn "Can't open $ARGV: $!n";
  while () {
    print;
  }
}

argument로 넘겨받는 파일이름에 대해서는 신경쓸 필요 없이 <>만 사용하면 각 파일에 대해서 open하고 읽어들이는 과정이 모두 자동적으로 실행되는 것이다.

b) 출력

print연산을 사용하는 경우에는 default로 출력의 방향이 STDOUT으로 정해진다. 그러므로 다음의 세 문장은 같은 의미를 가진다.

 

 

 

print "Hello worldn";
print STDOUT "Hello worldn"; 
print STDOUT Hello, " ", world, "n";

STDOUT뒤에 ,를 찍지 않도록 주의하자. STDOUT은 출력 대상이 아니라 출력의 방향이기 때문이다.

특정 파일에 대해서 출력을 하기 위해서는 미리 쓰기 mode로 open을 해야 하고 그 이후에 print 연산에 출력 방향으로 그 파일의 filehandle을 지정하면 된다.

 

 

 

open(OUTPUT, "> output.log");
print OUTPUT "Result : All men are alive.n");

shell에서 사용하던 방식의 token을 이용한 출력방법도 있다. 이것을 here document 문법이라고 하며 token을 일종의 quote로 생각하는 것이다. 여러 줄에 걸쳐진 출력에 대해서 문서를 쓰듯이 출력할 수 있다는 게 장점이다.

 

 

 

print OUTPUT << EOF
But most of payload are lost. 
Estimation of loss are still being carried.
EOF

print 연산자는 EOF라는 토큰을 quote로 간주하고 두개 사이의 텍스트를 지정된 출력방향으로 내보내게 된다. 토큰에 따라서 보다 정교한 출력 방법이 있는데, 여기서는 몇 가지만 더 살펴보기로 하겠다.

 

 

 

print << "" x 10
Hello, world!

이 예제는 quote가 null string이므로(그러므로 ""조차 생략 가능하다.) 다음 줄만을 출력 대상으로 삼게 되고 print 연산을 10번 수행하게 된다.

 

 

 

print << `ANYTOKEN`
id
echo hello
ANYTOKEN

token을 감싸는 것이 back-quote(backtick)임에 유의하라. back-quote는 명령을 실행시켜주는 역할을 한다. 그러므로 두 토큰 사이에 존재하는 id와 echo hello라는 명령이 실행된 결과가 출력되게 된다.

c) 에러 출력

에러는 파일로 보낼 수도 있지만, STDERR로 모아서 보내는 것이 일반적이다. 그러므로 print의 출력방향을 STDERR로 명시하면 된다.

 

 

 

print STDERR "Can't find such a file!n";

  4) 비교 연산자

Perl에서는 문자열에서 사용되는 논리연산자와 수치에서 사용되는 논리연산자가 따로 제공된다. 다음의 표를 참조하라.

 

 

 

비교 표현식 수치연산자 문자열연산자
같은가? == eq
같지 않은가? != neq
보다 작은가? < lt
보다 큰가? > gt
같거나 작은가? <= le
같거나 큰가? >= ge
같지 않은가? <=> cmp

 

 

 

 

 

$PROGRAM_NAME 현재 실행중인 Perl script의 이름을 지정하는 변수이다.
$[   배열의 첫 번째 원소의 index, 또는 substring의 첫 번째 글자의 index를 지정하는 변수이다. 기본적으로는 0번 원소부터 배열이 시작하지만, 1번 원소부터 배열이 시작하도록 1로 값을 바꿀 수 있다.
$] $PERL_VERSION Perl의 version과 patch level을 알려주는 변수로서, 5.004는 5번째 version에 4번째 patch level임을 의미한다.
$^D $DEBUGGING debugging flag(-D switch)가 켜져 있는지에 관한 정보를 담고 있는 변수이다.
$^F $SYSTEM_FD_MAX 현재 open되어 사용되고 있는 file descriptor의 최대 번호를 지정하는 변수이다. 보통 프로그램이 시작하게 되면 자동으로 0, 1, 2번이 STDIN, STDOUT, STDERR로 설정된다.
$^H   Perl compiler의 내부 컴파일 힌트에 관한 정보를 담는 변수이다.
$^I $INPLACE_EDIT inplace-edit extension의 값을 저장하는 변수이다. 이 값은 -i switch에 의해 지정된다.
$^O $OSNAME 현재 사용되고 있는 Operating System의 이름을 저장하는 변수이다.
$^P $PERLDB Perl debugger가 자신을 debug하지 않도록 꺼주는 내부 flag 변수이다.
$^T $BASETIME script가 실행되기 시작한 시각을 지정하는 변수이다. Unix system에서는 70년 1월 1일 0시 0분 0초(epoch)로부터의, 초단위 시간이다.
$^W $WARNING -w switch에 의해 지정되는 warning(경고) 여부의 값을 저장하는 변수이다.
$^X $EXECUTABLE_NAME Perl 바이너리가 실행 시에 가지게 되는 이름을 지정하는 변수이다.
$ARGV   argument로 넘겨져 들어온 파일의 이름이다.


다음의 예제는 동일한 의미를 가지는 코드이다.
 

$foo{$a, $b, $c}
$foo{join($;, $a, $b, $c)}


d) Global special array
 

@ARGV 넘겨져 들어온 command-line argument의 list를 저장하는 변수이다.
@INC do, require, use등의 operator를 사용할 때 필요한 Perl script를 찾는 디렉토리를 지정하는 변수이다. -I switch를 사용하여 지정된다. lib module을 사용하여도 지정 가능하다.
@F -a switch를 사용한 경우에, input line을 분리해 넣어줄 변수의 array를 지정하는 list 변수이다.
%INC module로 사용될 Perl script의 이름과 그 script의 절대경로를 저장해놓은 hash 변수이다.
%ENV shell에서 넘겨져 온 hash type의 환경변수이다. 환경변수의 이름과 그 값을 hash해 놓았다.
%SIG signal과 그에 해당하는 signal handler를 지정하는 hash 변수이다.


다음은 환경 변수를 지정하는 예제이다.
 

$ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin";


signal handler를 사용하는 예제를 참고하도록 하라. Ctrl-C를 눌러 interrupt를 걸게 되면 프로그램이 중단되게 되는데 INT signal을 가로채서 특정한 함수(signal handler)를 실행시키도록 할 수 있다.
 

sub sighandler {
  local($sig) = @_;
  print "Closing log file...n";
  close(LOG);
  exit(0);
}
$SIG{'INT'} = 'handler';


e) Global special Filehandles
 

ARGV @ARGV에서 저장된 argument로 넘겨진 file들을 다루는 filehandle이다. 는 <>로 줄여서 사용 가능하다.
STDERR standard error에 대한 filehandle이다.
STDIN standard input에 대한 filehandle이다.
STDOUT standard output에 대한 filehandle이다.
DATA Perl script에서 __END__라는 token뒤쪽에 나오는 모든 자료에 대한 filehandle이다.
_(underline) 마지막으로 다루었던 파일에 대한 정보를 cache로 저장하고 있는 filehandle이다.


  6) 레퍼런스(reference)

'레퍼런스'란 우리말로 옮기자면 '참조'라고 할 수 있다. 어떤 변수가 존재하고 그 이름을 저장함으로써 원래의 변수를 '참조'하는 다른 변수가 존재한다면 그 변수를 symbolic reference라고 한다. 반면에 hard reference라는 것도 있는데, 이것은 이름을 통해서가 아니라 실제의 값을 통해서 참조하게 된다. 여기에서는 hard reference에 더 중점을 두어 자세히 설명하려고 한다.

reference와 관련된 용어들에 대해서 잠깐 설명을 하고 넘어가자. reference를 만드는 것을 referece한다고 하면, 반대의 과정, 즉 참조 대상이 되는 변수나 상수의 값을 꺼내오는 것을 dereference한다고 한다. reference의 대상이 되는 것을 thingy(referent)라고 부른다. Perl의 저자인 Larry Wall이 thingy라는 표현을 고집하므로 여기서도 thingy라는 표현을 사용하도록 하겠다.

a) hard reference

hard reference가 가리키는 대상을 Perl에서는 흔히 thingy라고 지칭하는데, 이 thingy에 따라, hard reference를 만드는 방법은 조금씩 달라진다. 대상은 어떤 값이라도 가능한데, 여기서는 이름 있는 변수(named variable)와 서브루틴(named subroutine), 이름 없는 배열(anonymous array), 이름 없는 hash(anonymous hash), 이름 없는 서브루틴(anonymous subroutine), 파일핸들(filehandle)에 대해서 살펴보기로 하자.

우선 대개의 변수와 서브루틴은 이름을 가진다. 그러므로 이러한 일반적인 변수나 서브루틴에 대한 reference가 많이 필요하게 되며, hard reference는 (backslash)연산자를 사용함으로써 만들 수 있다.

 

$scalarref = $foo;  # $foo는 일반변수, 는 reference하는 연산자
$constref = 3.24;  # hard reference는 값에 대한 reference이다.
$arrayref = @array1; 
$hashref = %hash2; 
$globref = *STDOUT;  # *는 typeglob이며, 모든 타입을 가리킨다.
$subref = &subroutine3; 


간단히 일반화해보면, 어떤 형태의 변수나 상수에 대해서 그 앞에 연산자를 붙여주면 hard reference가 되는 것이다. reference를 통해서 그 값을 사용하기 위해서는 $, &, @, % 연산자 중의 하나를 reference변수 앞에 붙여주면 된다. reference는 그 대상(thingy)가 어떤 타입인지를 신경 쓰지 않기 때문에, 사용자가 타입 캐스팅을 하듯이 타입연산자인 $, %, &, @ 등의 연산자를 지정하는 것이 필수적이다.
 

print $$scalarref;  # print $foo;와 동일하다.
$$constref   # 3.24와 동일하다.
$$hashref{'key1'}   # $hash2{'key1'}과 동일하다.
&$subref;   # subroutine3를 호출하게 된다.
shift(@$arrayref);  # @array1에 대해 shift연산을 하는 것과 같다.


reference변수를 다시 reference할 수 있는데, 이럴 때에는 필요한 만큼 연산을 붙여 줄 수 있고, 값을 꺼낼 때에는 타입연산자의 수가 연산자의 수보다 하나 더 많은가를 확인해야 한다.
 

$multiref = 123;  # 123에 대해 연산을 4번 시행
print $$$$$multiref;  # $multiref에 대해서 $연산을 4번 시행


이번에는 이름 없는 배열과 해시와 서브루틴을 참조하는 hard reference를 다루는 법에 대해서 알아보도록 하자. 여기서 이름이 없다는 표현은, 이미 만들어져서 이름을 가지고 있는 변수나 상수의 값을 참조하는 게 아니라 reference를 만들면서 그것이 참조하는 thingy를 만들기 때문에 이름을 지어주지 못했다는 의미이다.
 

$arrayref = [1, 2, [3, 4, 5]];  # anonymous array reference
$hashref = {
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
};


$subref = sub { 
  print "When Harry met Sallyn"; # anonymous subroutine reference
};



위의 예제를 살펴보면, reference는 보이지 않고, 보통 variable에 값을 대입해 준 것처럼 보인다. 그러나 실제 assignment는 다음과 같다. 잘 비교해보도록 하자. 연산자로 사용되는 기호들이 약간씩 다르다는 것을 알게 될 것이다.
 

@array = (1, 2, (3, 4, 5));
%hash = (
  'Meg' => 'Ryan',   # anonymous hash reference
  'Billy' => 'Christal'
);
&subroutine1;
sub subroutine1 {
  print "Sleepless in Seattlen"; # anonymous subroutine reference
};


두 예제를 비교해 본 바와 같이, anonymous array reference는 [ ]을, anonymous hash reference는 { }를, anonymous subroutine reference는 sub { }를 연산자로 사용한다는 것을 알 수 있다.

b) hard reference in nested data structure

$연산자로 dereference하는 것 이외에도, ->연산자(arrow operator)를 사용해서 array나 hash의 값을 dereference하는 방법도 있는데, 이러한 방법들은 '배열의 배열'을 구현할 때 긴요하게 쓰인다. 다음은 같은 효과를 내는 연산자 사용에 대한 예이다.

 

$$arrayref[0] = "first";
${$arrayref}[0] = "first";
$arrayref->[0] = "first";

$$hashref{'key2'} = "McLean";
${$hashref}{'key2'} = "McLean";
$hashref->{'key2'} = "McLean";


->연산자는 dereference의 기능을 $연산자보다 더 직관적으로 제시하기 때문에 C프로그래밍에 익숙한 사용자에게 유용할 것이다. 다음은 ->연산자를 이용한 1차원 배열의 원소를 dereference하고, '배열의 배열'내의 원소를 dereference하는 방법을 보인 예이다.
 

$arrayref->[3] = "list-item1";

$arrayref->[3]->[4] = "multi-dimensional-item2";
$arrayref->[3][4] = "multi-dimensional-item2";
$$arrayref[3][4] = "multi-dimensional-item2";


C프로그래머에게는 '배열의 배열'을 나타내는 위의 표현 중에서 마지막 것이 친숙해 보일 수 있으나, Perl에서는 []연산자가 우선 순위(precedence)가 낮아서 reference가 어떻게 사용되고 있는지를 알아보기가 어렵다는 이유로 권하지 않는 방법이다. 그 위의 두 가지 방법을 이용하여 다중 배열을 나타내기로 한다.
 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

$ref_list_of_list = [
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
];
print $ref_list_of_list[0][2];      # terminator가 출력된다.
print $ref_list_of_list->[2][1];    # electronics가 출력된다.
print $ref_list_of_list->[1]->[3];  # signed가 출력된다.


만약 for loop를 사용해서 모든 원소를 출력하기를 원한다면, 각 sub list가 가지고 있는 원소의 개수를 알아야 하는데, length()함수를 써서 원소의 개수를 구해 내거나, $#연산자를 사용하여 리스트변수의 마지막 인덱스를 얻을 수 있다.

b) symbolic reference

symbolic reference는 reference가 가리키고 있는(여기서는 thingy가 아님을 유의할 것) 변수의 이름을 문자열로 해서 저장하게 된다. 다시 말해서 변수의 이름을 가진다는 것은 symbolic reference를 만드는 것이다. hard reference가 thingy를 직접 참고하는 것에 반해서 symbolic reference는 변수의 이름을 통해서 그 값에 접근하게 된다. 그러므로 항상 named variable에 대해서만 symbolic reference를 만들 수 있는 것이다.

symbolic reference를 만드는 것은 단순히 변수의 이름을 지정하기만 하면 되며, 그 사용법도 hard reference와 다르지 않다. 타입연산자를 앞에 붙여주면 그 값을 취할 수 있게 된다.

 

$var1 = "test";
$sr = "var1";
$$sr = "verify"; # $var1 eq "verify"

@var2 = ("hello", "program", "world");
$sr = "var2";
push(@$sr, "perl"); # @var2 eq ('hello', 'program', 'world', 'perl')


  7) 배열의 배열, 해시의 배열, 배열의 해시

배열의 배열은 사실상 Perl에서 제공하려고 의도하는 것은 아니다. Perl은 단순히 1차원의 배열만을 제공하는데, C와는 달리 scalar값이 놓일 위치에 vector형 변수가 놓일 수 있으므로 자연스럽게 배열의 배열, 해시의 배열, 배열의 해시 등과 같은 복합적인 data structure를 만들 수 있다.

a) 배열의 배열

다음과 같은 코드를 실행시켜 보자. 아마 아무 출력도 없을 것이다. 그 이유는 Perl이 1차원 배열만을 제공하기 때문에 $list_of_list[0][2]와 같은 형식은 무시되기 때문이다.(-w 스위치를 사용하면 warning을 볼 수 있다.)

 

@list_of_list = (
  ("separator", "delimiter", "terminator"),
  ("long", "short", "int", "signed", "unsigned"),
  ("physics", "chemistry", "computer"),
);


print $list_of_list[0][2]; 
print $list_of_list[2][1]; 
print $list_of_list[1][3];


2차원 배열을 구현하기 위해서는 reference를 이용해야 한다.
 

@list_of_list = (
  ["separator", "delimiter", "terminator"],
  ["long", "short", "int", "signed", "unsigned"],
  ["physics", "chemistry", "computer"],
);
print $list_of_list[0][2];  # terminator가 출력된다.
print $list_of_list[2][1];  # electronics가 출력된다.
print $list_of_list[1][3];  # signed가 출력된다.


b) 배열의 해시

리스트를 해시 값으로 사용하여 해시를 만드는 것도 비슷한 방법에 의해 가능하다.

 

%hash_of_list = (
  token => ["separator", "delimiter", "terminator"],
  type => ["long", "short", "int", "signed", "unsigned"],
  science => ["physics", "chemistry", "computer"],
);

print $hash_of_list{'token'}->[1]; # delimiter가 출력된다.
print $hash_of_list{'type'}[0];    # long이 출력된다.
print $hash_of_list{science};      # ARRAY(0xb2074)같은 정보가 출력된다.
print $hash_of_list{science}->[2]; # computer이 출력된다.
print @$hash_of_list{science};     # 아무 것도 출력되지 않는다.
print @{$hash_of_list{science}};   # physicschemistrycomputer 출력


c) 해시의 해시
 

%hash_of_hash = (
  token => {
    s => "separator", 
    d => "delimiter",
    t => "terminator"
  },
  type => {
    l => "long",
    s => "short",
    i => "int"
  },
  science => {
    e => "chemistry", 
    c => "computer",
  },
);

print $hash_of_hash{token}->{s}; # separator 출력
print $hash_of_hash{type}{i};    # int 출력
print $hash_of_hash{science};    # HASH(0xb205c)같은 정보가 출력된다.


다만 주의할 것은 해시나 리스트는 해시의 키(key)로 사용할 수 없다는 것이다. 이유는 key는 단순한 문자열로 취급이 되기 때문이다. 리스트나 해시를 넣는다고 해도 문자열 이상의 의미를 가지지는 못하게 된다.

2. 식(Expression)

  1) 기본 연산자

a) 수치 연산자

Perl은 수치에 대해서 사칙연산을 기본적으로 제공한다. +, -, *, /가 그에 해당하는 연산자이다. 그리고 FORTRAN과 같이 **에 의한 거듭제곱 연산도 가능하다. 나머지를 구하는 연산도 있는데, %를 연산자(operator)로 사용하며, 피연산자(operand) 모두를 정수로 취급한다. 반면에 나누기 연산자인 /는 피연산자 모두를 실수로 취급한다. 논리연산자인 <, <=, ==, >=, >, !도 사용 가능하다.

다음은 수치 연산자의 사용 예이다.
 

2 + 3  # 5
5.1 - 2.4 # 2.7
3 * 12  # 36
14 / 2  # 7
10.2 / 0.3 # 34
10 / 3  # 3.33333...

if (3 > 4) {
  print "3 is greater than 4.n";
} else {
  print "3 is not greater than 4.n";  # 비교문이 거짓이므로 여기가 실행됨
}


b) 문자열 연산자

문자열 연산자에는 C에서는 볼 수 없는 연산자들이 많이 등장한다. 우선은 문자열들을 붙이는 연산자인 .(dot)이 있고, 문자열을 정수번 반복해서 붙여주는 x연산자도 있다. 다음의 예제를 참고하도록 하자.
 

$b = "Hello, ";
$c = "world";
$a = $b . $c;  # $a = "Hello, world"

$a = "boy";
$b = $a x 3;  # $b = "boyboyboy"
$c = $a x 4.2;  # $b = "boyboyboyboy", 4.2는 4로 cast된다.


c) 대입연산자(assignment operator)

대입연산자에는 C와 마찬가지로 =이 기본적인 연산자이다. 이밖에도 C에서 사용하는 대입연산자들은 거의 Perl에서 채택되어져 있다. +=, -=, *=, /=, &=, |=. ^=, %=가 그 예이다. 그 밖에도 .=, x=, ||=, **=, <<=, >>=의 연산자들이 있다. 이와 같은 대입연산자들은 %연산, .연산, x연산, ||연산을 수행한 후에 그 결과를 대입하는 것이므로 보충 설명이 없어도 이해에 어려움이 없을 것이다.
 

$a *= 3;  # $a = $a * 3;
$b .= "n";  # $b = $b . "n"
$c ||= 2;  # $c = $c || 2, $c가 2가 아니면 2의 값을 대입한다.


d) 연산자 우선 순위와 결합법칙

여러 연산자들의 결합순위와 우선 순위를 다음의 표로 정리해놓았다. 위쪽에 있는 연산자일수록 아래쪽 연산자들보다 우선 순위가 높다. 같은 줄에 있는 연산자들은 같은 우선 순위 가지게 되고 결합순위에 따라 연산의 순서가 정해진다.
 

결합순위 연산자
없음 ++ --
! ~ -(단항연산)
**
=~ !~
* / % x
+ -(이항연산) .
<< >>
없음 file test operator
없음 named unary operator
없음 < <= > >= lt le gt ge
없음 == != <=> eq ne cmp
&
| ^
&&
||
없음 ..
?:(삼항연산)
대입 연산자 (+= -= 등)
,
없음 list 연산자


e) 수치와 문자열 상호변환

Perl은 수치와 문자열, 정수와 실수 사이의 변환을 자동으로 해준다. 수치 앞 뒤쪽에 오는 쓸데없는 문자들을 자동으로 제거해주므로 다음과 같은 연산이 가능하다.
 

$a = "   3.5abcd" * 4;
print $a;   # 3.5 * 4 = 14가 출력된다.
$b = "3" + "4";   # $b = 7


Perl이 자동으로 변환해 주는 것은 문자열 또는 수치가 이중적인 의미를 가질 때, 앞쪽이나 뒤쪽에 위치하는 연산자가 필요로 하는 피연산자가 수치인가 문자열인가를 결정할 수 있기 때문이다.
 

print "boy" . (3 * 2);  # boy6가 출력된다.
print "boy" x (3 * 2);  # boyboyboyboyboyboy가 출력된다.


괄호 안의 3 * 2이 먼저 수치로서 계산이 된다. 수치로 인식되는 이유는 *이 수치를 피연산자로 가지기 때문이다. 다음에는 문자열을 결합시켜주는 . 연산자를 만나게 되므로 (3 * 2)의 결과인 6을 문자열로 변환시켜서 인식하게 된다. 이러한 방식으로 자동변환이 일어나게 되므로 프로그래머는 사소한 것에 신경 쓰지 않아도 된다.

  2) 추가 연산자

또 하나 프로그래머가 매달릴 필요가 없는 것은 연산자를 연산자로 볼 것인가 함수로 볼 것인가의 문제인데, Perl에서 제공되는 대개의 연산자는 연산자이면서 함수로 볼 수 있기 때문에 C처럼 ()를 반드시 써 줄 필요가 없다.

a) scalar operator
 

rand $a 0과 $a 사이의 임의의 값(random number)을 반환한다. 0이상 $a미만의 범위의 소수를 구하게 된다.
srand $a random number를 만들어 낼 때 사용하는 seed값을 지정한다. srand(time^$$)처럼 현재시간을 알려주는 time연산자와 현재 프로세스의 번호를 지정하는 $$변수를 넣어서 사용하기도 한다.
substr $a, $b, $c $a라는 문자열에서 $b의 offset위치에 $c개만큼의 원소를 지정하게 된다. substr을 이용해서 $a에 새로운 값을 넣어주거나 $a에서 원소를 꺼내올 수 있다. $c부분은 생략 가능하다.
index $a, $b, $c 문자열 $a에서 $b가 나타나는 위치(offset)을 알려준다. $c부분은 찾기 시작하는 위치를 지정하는 것인데, 생략되면 0의 값이 대신 사용된다.
chop $a chop은 $a의 마지막 글자를 제거하는 연산자이며 Perl 5에서는 다음의 chomp을 권장한다. $a는 리스트라도 처리할 수 있다.
chomp $a chomp는 chop의 안전한 버전이며, $a의 마지막 글자가 $/변수($INPUT_RECORD_SEPARATOR, $RS)의 값을 가지면 제거하는 역할을 한다. 대개는 입력에 붙어서 들어오는 newline character를 제거할 때 사용한다.


b) vector operator
 

shift @a 리스트 @a의 가장 앞쪽에 있는 원소를 꺼내준다.
unshift @a, $b $b를 @a의 가장 앞쪽에 쑤셔 넣어 준다.
pop @a @a의 가장 뒤쪽에 있는 원소를 꺼내준다.
push(@a, $b) @a의 가장 뒤쪽에 $b를 추가해준다.
splice @a, $b, $c, @d; @a의 offset이 $b되는 곳에서 $c개의 원소를 지정할 때 사용한다. @d가 사용되는 경우에는 @d를 $c개의 원소와 바꾸어준다. @d가 생략되면 $c개의 원소를 반환한다.
keys %a 해시 변수 %a의 key를 모아서 리스트 형태로 반환한다.
$a .. $b ..은 범위연산자(range operator)라고 하는데, $a에서 $b까지의 값을 리스트 형태로 반환한다. $a와 $b에 들어갈 수 있는 값은 정수나 문자이다. 문자열을 사용하면 그 사이에 존재할 수 있는 모든 문자열 조합을 만들어 주기도 하는데, 시스템의 자원을 낭비하기 쉬우므로 조심해야 한다.
, comma(,) 연산자는 리스트에서 separator로 사용되는 comma와는 다른 의미를 가진다. comma 연산자는 ,뒤쪽의 값을 반환한다. ,로 여러 개의 값이 나열되면 마지막 값이 리턴 된다.
sort @a 리스트변수 @a를 정렬해준다. sort의 기준을 제시하는 비교함수나 블럭을 지정할 수도 있는데, 리스트 앞에 지정해준다. 이 때 비교함수나 블럭에서는 <=>, cmp 연산자와 논리연산자등을 사용하여 +1, -1, 0등의 값을 반환하도록 한다.
reverse @a 리스트의 원소의 순서를 반대 방향으로 바꾸어준다.
grep PATTERN, @a
grep FILETEST, @a
리스트변수 @a를 읽어들여 패턴매치나 파일 테스트를 해서 성공할 경우, 그 리스트의 원소인 line이나 string을 반환한다.
join $b, @a @a의 원소들을 $b를 delimiter로 하여 묶어 하나의 문자열로 반환한다.
split PATTERN, $a, $b 문자열 $a를 PATTERN에 나오는 character를 delimiter로 해서 나누어 리스트형태로 반환한다. $b를 사용하게 되면 그 값에 해당하는 개수까지 원소들을 생성해준다.


c) file test operator

다음은 파일에 대한 조건식을 만드는 operator을 정리한 표이다. 다음의 테스트는 참/거짓의 값을 가지거나 특정한 결과 값을 return해 준다.
 

-r 파일을 읽을 수(readable) 있는가?
-w 파일을 쓸 수(writable) 있는가?
-x 파일을 실행시킬 수(executable) 있는가?
-o 파일이 $euid의 사용자 소유인가?
-R 파일이 $uid의 사용자에 의해 읽혀질 수 있는가?
-W 파일이 $uid의 사용자에 의해 쓰여질 수 있는가?
-X 파일이 $uid의 사용자에 의해 실행가능한가?
-O 파일이 $uid의 사용자 소유인가?
-e 파일이 존재하는가?
-z 파일의 크기가 0인가?
-s 파일의 크기(size)
-f 파일이 정규파일(디렉토리가 아닌)인가?
-d 파일이 디렉토리인가?
-l 파일이 symbolic link인가?
-p 파일이 FIFO와 같은 named pipe인가?
-S 파일이 socket인가?
-b 파일이 block special file인가?
-c 파일이 character special file인가?
-t filehandle이 tty(terminal)에 열려 있는가?
-u setuid bit이 켜져 있는 파일인가?
-g setgid bit이 켜져 있는 파일인가?
-k sticky bit이 켜져 있는 파일인가?
-T 파일이 텍스트(text) 파일인가?
-B 이진(binary) 파일인가?
-M file의 최종 수정 시간(modification time, mtime)
-A file의 최종 접근 시간(last access time, atime)
-C file의 최종 변경 시간(inode change time, ctime)


다음은 file test를 이용한 조건식의 예이다.
 

while (<>) {
  chomp;   # default input string의 마지막 n을 제거한다.
  next unless -f $_;  # 정규파일이 아닌 경우에는 다음으로 넘어간다.
}

stat($file);
print "Readablen" if -r _; # _는 마지막으로 사용된 filehandle이다.
print "Writablen" if -w _; # readable, writable, executable한지 체크한다.
print "Executablen" if -x _;

&newfile if -M $file < 5; # mtime이 5일 이내라면 서브루틴을 호출한다.


  3) 기본 입출력 연산자

입출력이란 프로그램이 자료를 외부세계에서 넘겨받고 그 자료를 처리한 결과를 외부세계에 넘겨주는 과정을 의미한다. Perl에서 가능한 방법은 파일을 이용한 것이고, 프로그래머는 filehandle이라는 것을 가지고 파일을 다룰 수 있게 된다. 파일을 열어서 filehandle을 지정하는 것은 open함수를 사용하면 되고, 더 이상 사용하지 않게 된 파일을 닫고 filehandle의 사용을 포기하는 것은 close함수를 이용하면 된다.

그러나 입출력 과정에 filehandle을 매번 사용한다는 것은 프로그램 작성에 상당한 불편을 안겨줄 것이다. 그리하여 Perl에서는 Unix시스템과 마찬가지로 표준입력(STDIN), 표준출력(STDOUT), 표준에러(STDERR)를 제공한다. 표준입력이란 키보드를 통해 자료를 입력받거나, 다른 프로그램에서 파이프나 redirection을 통해 자료를 넘겨받는 것이다. 반면에 표준출력은 print 연산이나 printf를 통해서 화면으로 결과를 출력하는 것이고, 표준에러는 화면에 에러메시지를 보여주는 것이다.

a) 입력

일반적으로 키보드로부터의 입력은
 

$input = ;
@input = ;


과 같은 형태로 받아들일 수 있다. $input이나 @input에는 사용자가 키보드를 통해 눌렀던 모든 키 입력이 문자열 또는 리스트의 형태로 저장된다.

Perl에서 즐겨 사용되는 입력방식에는 다음과 같은 것들이 있다. 짧은 코드에서 긴 코드까지 모두 같은 효과를 가지며, 문맥적으로 같은 의미를 가진다.
 

print while 
print $_ while ;
print $_ while definded($_ = );
for (;;) { print; }
for (;;) { print $_; }
while () { print; }
while () { print $_; }
while (defined($_ = )) { print $_ };


$_는 default input string을 저장하는 변수로서 대개의 연산자에서 생략 가능하다. 거꾸로 말해서, 연산자만 나오는 경우는 대개 $_를 염두에 둔 것이라고 볼 수 있다. 에서 들어온 모든 입력은 $_에 자동으로 저장된다. $_대신에 다른 변수를 사용해도 별로 상관은 없으나, 생략해서 사용할 수는 없다.

STDIN같은 표준입출력에 관련된 filehandle은 굳이 open의 과정이 필요 없으나, 일반적인 파일에 대한 filehandle은 open의 과정이 명시되어야 한다.

 

 

 

open(FILE, "test.c");
$_ = ;
print;

이 예제는 test.c라는 파일을 FILE이라는 filehandle을 통해서 다루게 되고 default input string에 한 줄 입력을 받아서 그것을 다시 출력해주는 작업을 하게 된다. 그러나 대개는 한 줄만 입력을 받는 게 아니라 파일 전체에 대해서 여러 줄의 입력을 받아야 하므로 loop안에서 사용하거나 리스트에 저장했다가 shift연산자를 사용하여 꺼내어 사용할 수 있다. 그러나 리스트에 파일의 큰 내용이 저장되는 것은 시스템에 부하를 주게 되므로 loop를 사용하는 방법을 익히도록 하자.

 

 

 

while ($input = ) {
  print "/* $input */n";
}

이 예제는 FILE을 통해 $input에 입력을 받고 그 line을 comment기호로 감싸는 작업을 수행하는 것이다.

Perl 프로그램이 filter로 사용되는 게 아니라면 대개는 프로그램의 argument로 파일 이름을 넘겨받아 사용하게 되는데, 이것은 아주 간단하다. 다음은 argument로 넘겨진 모든 파일을 열어서 한 줄씩 입력을 받아서 출력하는 예이다.

 

 

 

while (<>) {
  print;
}

이 코드는 다음과 동일한 의미를 가진다.

 

 

 

@ARGV = ('-') unless @ARGV;
while ($ARGV = shift) {
  open(ARGV, $ARGV) or warn "Can't open $ARGV: $!n";
  while () {
    print;
  }
}

argument로 넘겨받는 파일이름에 대해서는 신경쓸 필요 없이 <>만 사용하면 각 파일에 대해서 open하고 읽어들이는 과정이 모두 자동적으로 실행되는 것이다.

b) 출력

print연산을 사용하는 경우에는 default로 출력의 방향이 STDOUT으로 정해진다. 그러므로 다음의 세 문장은 같은 의미를 가진다.

 

 

 

print "Hello worldn";
print STDOUT "Hello worldn"; 
print STDOUT Hello, " ", world, "n";

STDOUT뒤에 ,를 찍지 않도록 주의하자. STDOUT은 출력 대상이 아니라 출력의 방향이기 때문이다.

특정 파일에 대해서 출력을 하기 위해서는 미리 쓰기 mode로 open을 해야 하고 그 이후에 print 연산에 출력 방향으로 그 파일의 filehandle을 지정하면 된다.

 

 

 

open(OUTPUT, "> output.log");
print OUTPUT "Result : All men are alive.n");

shell에서 사용하던 방식의 token을 이용한 출력방법도 있다. 이것을 here document 문법이라고 하며 token을 일종의 quote로 생각하는 것이다. 여러 줄에 걸쳐진 출력에 대해서 문서를 쓰듯이 출력할 수 있다는 게 장점이다.

 

 

 

print OUTPUT << EOF
But most of payload are lost. 
Estimation of loss are still being carried.
EOF

print 연산자는 EOF라는 토큰을 quote로 간주하고 두개 사이의 텍스트를 지정된 출력방향으로 내보내게 된다. 토큰에 따라서 보다 정교한 출력 방법이 있는데, 여기서는 몇 가지만 더 살펴보기로 하겠다.

 

 

 

print << "" x 10
Hello, world!

이 예제는 quote가 null string이므로(그러므로 ""조차 생략 가능하다.) 다음 줄만을 출력 대상으로 삼게 되고 print 연산을 10번 수행하게 된다.

 

 

 

print << `ANYTOKEN`
id
echo hello
ANYTOKEN

token을 감싸는 것이 back-quote(backtick)임에 유의하라. back-quote는 명령을 실행시켜주는 역할을 한다. 그러므로 두 토큰 사이에 존재하는 id와 echo hello라는 명령이 실행된 결과가 출력되게 된다.

c) 에러 출력

에러는 파일로 보낼 수도 있지만, STDERR로 모아서 보내는 것이 일반적이다. 그러므로 print의 출력방향을 STDERR로 명시하면 된다.

 

 

 

print STDERR "Can't find such a file!n";

  4) 비교 연산자

Perl에서는 문자열에서 사용되는 논리연산자와 수치에서 사용되는 논리연산자가 따로 제공된다. 다음의 표를 참조하라.

 

 

 

비교 표현식 수치연산자 문자열연산자
같은가? == eq
같지 않은가? != neq
보다 작은가? < lt
보다 큰가? > gt
같거나 작은가? <= le
같거나 큰가? >= ge
같지 않은가? <=> cmp

 

 

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
1191 [ 一日30分 인생승리의 학습법] REST, REST API, RESTful 과 HATEOAS file 졸리운_곰 2024.03.10 7
1190 [ 一日30分 인생승리의 학습법] 렌더링 삼형제 CSR, SSR, SSG 이해하기 file 졸리운_곰 2024.03.10 1
1189 [ 一日30分 인생승리의 학습법] 엑셀 VBA에서 셀레니움 사용을 위한 Selenium Basic 설치 file 졸리운_곰 2024.02.23 9
1188 [ 一日30分 인생승리의 학습법]500 Lines or Less Blockcode: A Visual Programming Toolkit : 500줄 이하의 블록코드: 시각적 프로그래밍 툴킷 졸리운_곰 2024.02.12 3
1187 [ 一日30分 인생승리의 학습법] 구글 클라이언트(앱) 아이디를 발급받으려면 어떻게 해야 하나요? 졸리운_곰 2024.01.28 2
1186 [ 一日30分 인생승리의 학습법] 빅뱅 프로젝트를 성공적으로 오픈하기 위한 팁 졸리운_곰 2023.12.27 14
1185 [ 一日30分 인생승리의 학습법]“빅뱅 전환보다 단계적 전환 방식이 이상적 애자일팀과 협업 쉽게 체질 개선을” file 졸리운_곰 2023.12.27 6
1184 [ 一日30分 인생승리의 학습법] Big-bang / phased 접근 file 졸리운_곰 2023.12.27 2
1183 [ 一日30分 인생승리의 학습법] CodeDragon 메뉴 데이터 전환의 개념 이해 - 데이터 전환의 개념, 데이터 전환방식, 데이터 전환방식 및 장단점 비교, 데이터전환 이후 검토해야 할 사항 졸리운_곰 2023.12.27 4
1182 [ 一日30分 인생승리의 학습법] 블록체인과 IPFS를 이용한 안전한 데이터 공유 플랫폼 - 분쟁 해결 시스템 file 졸리운_곰 2023.12.27 5
1181 [ 一日30分 인생승리의 학습법] 블록체인과 IPFS를 이용한 안전한 데이터 공유 플랫폼 - 개념과 리뷰 시스템 file 졸리운_곰 2023.12.27 3
1180 [ 一日30分 인생승리의 학습법] 소켓 CLOSE_WAIT 발생 현상 및 처리 방안 file 졸리운_곰 2023.12.03 6
1179 [ 一日30分 인생승리의 학습법] robots 설정하기 졸리운_곰 2023.12.03 2
1178 [ 一日30分 인생승리의 학습법] A Tutorial and Elementary Trajectory Model for the Differential Steering System of Robot Wheel Actuators : 로봇 휠 액츄에이터의 차동 조향 시스템에 대한 튜토리얼 및 기본 궤적 모델 file 졸리운_곰 2023.11.29 5
1177 [ 一日30分 인생승리의 학습법] Streamline Your MLOps Journey with CodeProject.AI Server : CodeProject.AI 서버로 MLOps 여정을 간소화하세요 file 졸리운_곰 2023.11.25 1
1176 [ 一日30分 인생승리의 학습법] Comparing Self-Hosted AI Servers: A Guide for Developers / : 자체 호스팅 AI 서버 비교: 개발자를 위한 가이드 file 졸리운_곰 2023.11.25 8
1175 [ 一日30分 인생승리의 학습법] Self-Hosted Artificial Intelligence: Keeping Control of Your Data : 자체 호스팅 인공 지능: 데이터 제어 유지 file 졸리운_곰 2023.11.25 5
1174 [ 一日30分 인생승리의 학습법] AI_머신러닝 기초 정리 file 졸리운_곰 2023.11.24 14
1173 [ 一日30分 인생승리의 학습법] 머신러닝 내용 요약 및 정리 졸리운_곰 2023.11.24 9
1172 [ 一日30分 인생승리의 학습법] 당신이 알아두어야 할 10가지 머신러닝 알고리즘 file 졸리운_곰 2023.11.24 7
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED