더 많은 정보를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.

https://reakwon.tistory.com/233

 

리눅스 프로그래밍 note 배포

티스토리에 리눅스에 관한 내용을 두서없이 여지껏 포스팅했었데요. 저도 제 포스팅을 찾기가 어렵기도 하고 티스토리에서 코드삽입을 하게 되면 이게 일자로 쭉 쓰여져있는 x같은 현상이 생겨

reakwon.tistory.com

AWK(Aho Weinberger Kernighan)

리눅스의 어떤 다른 명령어보다 명령어 이름이 매우 직관적이지 않은 명령어입니다. 이 명령어를 개발한 사람들의 이름 약자(Aho  Weinberger Kernighan)이기 때문에 mkdir(make directory), rm(remove) 같은 의미를 축약하여 만든 명령어와는 명령어 이름이 좀 그렇습니다. 이 명령어를 읽을때는 주로 오크라고 읽습니다. AWK는 유닉스에서 개발된 스크립트 언어로 텍스트가 저장되어 있는 파일을 원하는 대로 필터링하거나 추가해주거나 기타 가공을 통해서 나온 결과를 행과 열로 출력해주는 프로그램입니다. 엄청나게 막강하고 다양한 기능을 담고 있기 때문에 여기서는 어떻게 사용하는지에 대해서만 알아보도록 하겠습니다.

그 전에 간단하게 기본 용어만 짚고 넘어가도록 합시다. 아래는 하나의 텍스트 파일에 기록된 내용을 보여주고 있습니다. 여기서 각 단어들은 공백으로 구분되어 집니다. 각 줄(line)은 레코드(Record)라고 칭합니다. 그리고 그 안에 각각의 단어들이 필드(Field)가 되겠습니다.

 

AWK에서는 레코드가 $0, 그리고 $1, ..., $N 은 필드를 나타내는 열을 나타냅니다. 우리들이 사용할 파일은 위 내용은 아니고 아래의 내용을 담고 있습니다. 

 

file : awk_test_file.txt

name    phone           birth           sex     score
reakwon 010-1234-1234   1981-01-01      M       100
sim     010-4321-4321   1999-09-09      F       88
nara    010-1010-2020   1993-12-12      M       20
yut     010-2323-2323   1988-10-10      F       59
kim     010-1234-4321   1977-07-17      M       69
nam     010-4321-7890   1996-06-20      M       75

 

awk의 기본 사용법은 패턴(pattern)액션(action)을 정의하여 입력으로 주어진 파일의 데이터를 가공하여 출력합니다. 이제부터 예를 볼 겁니다. 패턴과 액션 중 하나만 사용하여도 무관합니다.

awk pattern {action} 

 

1. 열(Column)만 출력하기

각 $1, $2, $3 ... 은 열에 대응한다고 했었죠. 그리고 $0는 레코드에 대응한다고 했습니다. 여기서 이름만 모두 출력하겠다고 한다면 아래와 같이 awk 명령을 수행하면 됩니다.

awk '{ print $1 }' ./awk_test_file.txt
name
reakwon
sim
nara
yut
kim
nam

 

여러개의 열도 출력 가능합니다.

 awk '{ print $1,$2 }' ./awk_test_file.txt
name phone
reakwon 010-1234-1234
sim 010-4321-4321
nara 010-1010-2020
yut 010-2323-2323
kim 010-1234-4321
nam 010-4321-7890

 

여기서 awk의 기본적인 action은 print이며 모든 열을 전부 출력합니다.

2. 특정 pattern이 포함된 레코드 출력

다음의 awk 명령은 rea라는 문자열이 포함된 레코드를 출력해주는 명령입니다. 

 awk '/rea/' ./awk_test_file.txt
reakwon 010-1234-1234   1981-01-01      M       100

 

3. 출력의 내용 첨가

awk는 print에 문자열을 추가하여 출력물의 내용에 문자열을 추가할 수 있습니다. 만약 이름을 명시적으로 나타내기 위해 "name : " , 그리고 휴대폰 번호를 명시적으로 나타내려고 "phone : " 를 추가해서 출력하고 싶다면 아래의 awk 명령을 사용하면 됩니다.

awk '{ print ("name : " $1, ", "  "phone : " $2) }' ./awk_test_file.txt

아래 출력에서 맨 윗줄은 무시하시면 됩니다.

name : name , phone : phone
name : reakwon , phone : 010-1234-1234
name : sim , phone : 010-4321-4321
name : nara , phone : 010-1010-2020
name : yut , phone : 010-2323-2323
name : kim , phone : 010-1234-4321
name : nam , phone : 010-4321-7890

 

4. 특정 Record를 검색하기 - if 구문

4-1. ~이상 , ~ 이하의 레코드 출력

만약 위의 파일에서 점수가 80점 이상인 사람들의 레코드를 알고 싶다면 어떻게 하면 좋을까요? 이거는 pattern을 써야할까요, action을 써야할까요? action에서는 if 구문이 존재합니다. 그래서 이렇게 사용하면 80점 이상인 record를 출력할 수 있습니다.

awk '{ if ( $5 >= 80 ) print ($0) }' ./awk_test_file.txt
name    phone           birth           sex     score
reakwon 010-1234-1234   1981-01-01      M       100
sim     010-4321-4321   1999-09-09      F       88

 

혹은 아래와 같은 구문으로도 사용할 수도 있습니다.

awk '$5 >= 80 { print $0 }' ./awk_test_file.txt

 

4-2. 남자의 데이터만 출력하기

역시 if 구문으로 지정할 수 있는데 단어 자체가 같은 것을 비교하려면 쌍따옴표(")해주면 됩니다. 

awk '{ if ( $4 == "M" ) print ($0) }' ./awk_test_file.txt
reakwon 010-1234-1234   1981-01-01      M       100
nara    010-1010-2020   1993-12-12      M       20
kim     010-1234-4321   1977-07-17      M       69
nam     010-4321-7890   1996-06-20      M       75

 

4-3. 다중 조건을 활용하여 남자이면서 80점인 레코드 출력하기

여러 조건을 걸고 싶다면 어떻게 할까요? 다른 프로그래밍 언어와 유사하게 AND(&&) 조건과 OR(||) 조건을 활용할 수 있습니다. 여기서는 위의 두 조건을 && 묶어서 사용하면 됩니다. ||을 사용하면 OR조건으로 출력됩니다.

awk '{ if ( $4 == "M" && $5 >= 80) print ($0) }' ./awk_test_file.txt
reakwon 010-1234-1234   1981-01-01      M       100

 

5. 내장 함수

awk에는 여러가지 내장함수들이 존재합니다. 단어의 길이를 알아내려면 length함수, 단어의 부분단어를 추출하려면 substr함수를 사용할 수 있습니다. 아래의 awk 명령은 이름의 길이와 이름의 3글자까지 출력을 하는 명령입니다.

 awk '{ print ("name leng : " length($1), "substr(0,3) : " substr($1,0,3)) }' ./awk_test_file.txt

name leng : 4 substr(0,3) : nam
name leng : 7 substr(0,3) : rea
name leng : 3 substr(0,3) : sim
name leng : 4 substr(0,3) : nar
name leng : 3 substr(0,3) : yut
name leng : 3 substr(0,3) : kim
name leng : 3 substr(0,3) : nam

 

이밖에도 모두 소문자로 출력하는 tolower함수, 모두 대문자로 출력하는 toupper 도 있습니다. 문자열을 쪼개는 split함수도 존재합니다. 여러 내장함수들이 있으니 필요시에 따라 사용하면 됩니다. 무엇이 있는지 어떻게 보냐구요? man 1 awk를 보시면 됩니다.

6. 반복문

반복문도 사용할 수 있습니다. C언어를 배우시는 분에게는 너무 익숙한 문법으로 사용할 수 있습니다. 아래는 단지 별의미 없이 for문의 사용법을 보여드리려 print를 2번까지 진행한 것입니다. 

awk '{
for(i=0;i<2;i++)
 print( "for loop :" i "\t" $1, $2, $3)
}' ./awk_test_file.txt
for loop :0     name phone birth
for loop :1     name phone birth
for loop :0     reakwon 010-1234-1234 1981-01-01
for loop :1     reakwon 010-1234-1234 1981-01-01
for loop :0     sim 010-4321-4321 1999-09-09
for loop :1     sim 010-4321-4321 1999-09-09
for loop :0     nara 010-1010-2020 1993-12-12
for loop :1     nara 010-1010-2020 1993-12-12
for loop :0     yut 010-2323-2323 1988-10-10
for loop :1     yut 010-2323-2323 1988-10-10
for loop :0     kim 010-1234-4321 1977-07-17
for loop :1     kim 010-1234-4321 1977-07-17
for loop :0     nam 010-4321-7890 1996-06-20
for loop :1     nam 010-4321-7890 1996-06-20

 

7. BEGIN, END pattern

BEGIN은 awk가 모든 레코드를 돌기 전에 한번 action을 수행하고 END는 모든 레코드를 다 돈 후에 마지막으로 정의한 action이 실행됩니다. 아래의 예에서 어떻게 사용되는지 살펴봅니다.

8. 변수 사용

awk 역시 언어이기 때문에 변수를 사용할 수 있습니다. 만약 우리가 위의 파일에서 총점과 평균을 구하고 싶다면 어떻게 하면 좋을까요? 레코드를 돌면서 각각의 점수를 더하면서 총점을 구하고, 총점을 사람의 수로 나누면 되지요. 그래서 구한 결과는 레코드가 끝난 마지막에 출력하면 되니 아까 이야기했던 END 패턴을 앞에 명시해줍니다. 아래의 awk가 그 명령입니다. 여기서 cnt가 -1부터 시작인 이유는 실제 레코드가 아닌 헤더가 존재하기 때문입니다. 이건 인원으로 볼 수 없죠. (name phone  birth  sex  score)

 awk '
> BEGIN {
>  sum = 0
>  cnt = -1
> }
>
> {
>  sum += $5
>  cnt++
> }
>
> END {
>  avg = sum/cnt
>  print ("sum :" sum ", average :" avg)
> }' ./awk_test_file.txt

 

BEGIN에서는 초기화가 이루어지고, END에서는 결과를 출력해줍니다. 프로그래밍 언어를 배우셨다면 cnt++이나 sum +=$5의 구문이 무엇인지 아실겁니다. 모르시는 분은 구글 서치해보세요. 어렵지 않습니다.

 

이상으로 awk에 대한 사용법과 내용을 추출하는 여러가지 예제를 보았습니다. 깊이 알면 좋지만 저는 그렇게 깊이 알아서 사용할 일은 없어 여기까지만 설명하도록 하겠습니다.

반응형
블로그 이미지

REAKWON

와나진짜

,