예제로 배우는 AWK/필드와 레코드

위키책, 위키책

기본적으로 AWK는 모든 자료를 레코드(Record)와 필드(Field)로 구분하여 처리한다. 한마디로 표(table)로 되어 있는 자료를 다루는 것이다. 여기서 필드는 자료에서의 열에 해당될 수 있고, 레코드는 자료에서의 행에 해당될 수 있다. 다음 예시를 살펴보면 필드와 레코드의 의미가 보다 명확해 질 것이다.

$1       $2       $3         
apple    45       Brazil     
grape    35       Italia     
melon    100      Brazil     

$1이 표시되어 있는 apple, grape, 그리고 melon이 들어있는 열이 첫번째 필드이다. 이런 식으로 $2가 표시된 열은 두번째 필드, $3이 표시된 열은 세번째 필드이다. 여기서 각각의 필드 위에 $1, $2, $3, $4라고 쓰여져 있는 것들은 오크 언어에서 각각의 필드에 들어 있는 내용을 가리킬 때 쓰는 약속이다. apple, 45, 그리고 Brazil이 들어있는 행이 첫번째 레코드이고, 그 다음은 두번째 레코드, 다음은 세번째 레코드이다. 즉, 이 자료는 3개의 레코드와 4개의 필드로 구성된 자료이다.


Excel과 AWK 언어 비교[+/-]

위에서 살펴본 것처럼 AWK가 모든 자료를 필드와 레코드로 구분하여 처리한다는 것은, 즉 일종의 표(table)로 되어 있는 자료를 다룬다는 것은 AWK과 Excel가 사실상 똑같은 데이터를 다룬다는 것을 알려준다. 겉보기에는 전혀 달라 보이는 경우도 있지만, 엑셀이 다루는 자료와 오크 언어가 다루는 자료는 기본적으로 똑같은 방식으로 구성이 된 것이다. 엑셀에서는 사용자가 보기 좋게 칸을 잘 나누어서 보여주고, AWK는 그렇게 보여주는 화면이 없다는 정도가 차이가 있다. Excel과 AWK의 차이는 처리속도와 편의성라고 할 수 있다. Excel의 경우, 처리할 수 있는 레코드의 개수가 65536를 넘지 못하는 반면, AWK는 처리할 수 있는 데이터의 크기에 전혀 제한이 없다. 자료의 크기가 조금만 커져버린다면, 엑셀의 경우 신속하게 처리되지 못하고 간혹 컴퓨터가 멈춰 버리는 일까지 생길 수도 있다. 반면, AWK는 사용자가 원하는 데이터를, 비록 그 데이터의 크기가 수십억개라고 할지라도 순식간에 처리해 버린다. 이런 면에서 AWK가 Excel에 비해 보다 경제적이라고 할 수 있다.


기본 필드 구분자(Default Field Seperator)[+/-]

AWK가 신속하고 정확하게 사용자가 지정하는 일을 처리하기 위해서는 AWK가 처리해야 하는 자료 구조(Data Structure)가 잘 짜여있어야 한다. 즉, 자료 안에 각각 레코드와 필드가 명확하게 구분되어 있어야 한다.

  • 레코드 구분자: 엔터(enter) 키
  • 필드 구분자: 탭(tab), 스페이스(space)

예를 들어서 아래와 같은 자료의 경우,

apple<tab>banana<tab>2007<tab>high<enter>
grape<space>melon<space>2008<space>low<enter>

AWK의 경우에는, 아래와 같이 레코드와 필드로 구분되어 표시된다.

apple    banana    2007    high     
grape melon 2008 low

첫번째 레코드의 경우에는 필드 구분자로 탭을 지정했고, 두번째 레코드의 경우에는 필드 구분자로 스페이스로 구분했기 때문에 각 필드와 필드 사이의 공백의 크기 정도는 달라보이지만 두 경우 모두 4개의 필드로 정확하게 구분된다.

또한 만약 아래와 같은 경우,

apple<tab>banana<tab><tab><tab>grape<enter>
grape<tab>watermelon, banana<tab><tab>apple<enter>

다음과 같이 처리된다.

apple   banana                   grape     
grape   watermelon, banana       apple           

위의 경우 첫번째 레코드에서 banana와 grape 사이에 탭이 3개나 있어도 banana와 grape 사이에 다른 내용이 입력되지 않았기 때문에 그 사이에는 또다른 필드는 없다. 즉, 탭이나 스페이스가 몇개씩 겹쳐서 나온다고 할지라도 그 사이에 내용이 없는 한 1개의 필드로 처리된다는 말이다.

필드 출력하기: print[+/-]

출력하기의 명령어로는 print를 사용한다.데이터에서 원하는 필드를 지정하여 출력하고자 하는 경우에는 다음과 같이 입력한다.

print $n;

이는 n번째 필드를 출력하라는 명령어이다. AWK에서 필드 내용을 가리킬 때 $ 문자를 사용하는데 $ 문자 뒤에 자신이 원하는 필드의 숫자를 입력하면 원하는 필드를 지정할 수 있다. 여기서 ;은 하나의 명령이 끝난다는 것을 알려준다.

만약 데이터의 첫번째 필드를 출력하고 싶은 경우에는, 아래와 같이 프로그램을 짜면 된다.

 {
          print $1;
 }

프로그램을 짤 때는 먼저 {}를 이용하여서 시작과 끝을 표시해준다. {} 안에 자신이 원하는 명령어를 입력하는데, 특정 필드를 출력하고자 하니 print 명령어를 입력한다.

이 프로그램을 시행시키고 싶은 경우에는 다음과 같이 명령을 내린다.

 $ gawk -f (위의 프로그램의 이름) (사용하고픈 데이터의 이름)

만약 위의 프로그램의 이름이 print1.awk이고 내가 사용하고 싶은 데이터의 이름이 data.txt라면 다음과 같이 입력하면 된다.

 $ gawk -f print1.awk data.txt

그러면 data.txt의 첫번째 필드만 화면에 출력될 것이다.

필드구분자를 자기가 원하는 대로 정해 줄수도 있다. 아래처럼 BEGIN 구분에 FS라는 변수를 원하는 문자로 지정해 주면 된다. 여기서 FS는 필드 구분자(Field Seperator)라는 의미이다. 예를 들어서 탭으로 구분된 자료에서 세번째 필드를 출력하고 싶은 경우에는 다음과 같이 프로그램을 짜면 된다.

 BEGIN {
       FS = "\t"
 }
 {
       print $3;
 }

이 프로그램을 위에서 말한 방법으로 시행시키면 데이터의 필드들을 tab으로 구분하여 세번째 필드의 화면에 출력할 것이다.

레코드의 개수와 필드의 개수(NR과 NF)[+/-]

  • NR(Number of Input Record): AWK가 곧 현재까지 읽어 들인 줄(=레코드=라인)의 개수를 의미한다. 즉, AWK가 몇번 작업을 반복했는지 알려주는 횟수라고도 할 수 있다. NR은 작업이 진행됨에 따라 순차적으로 1씩 증가한다.
  • NF(Number of Fields): AWK가 읽어 들인 레코드 안의 필드의 개수를 의미한다. NR과 달리 작업이 진행됨에 따라 순차적으로 1씩 증가하거나 하지 않는다.