Contents

System/OS
2014.03.11 11:19

[linux] awk 명령어

조회 수 4943 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
1. awk 명령어 개요
awk라는 이름은 이를 개발한 세 사람의 이름 Aho, Weinberger, Kernighan에서 유래된 것이다.
awk명령어는 일련의 입력 파일을 읽어 지정된 패턴과 일치하는 패턴을 간직한 라인을 찾는다.
패턴이 일치하면 지정된 연산이 실행된다.
여기서의 연산은 라인 내의 필드 조작이나 필드값을 이용한 산술 연산을 의미한다.
이 awk는 shell programming과 bc 그리고 C 프로그래밍언어의 기능을 갖춘 프로그래밍 언어로 bc와 같이 완벽하게 해독이 되며 쉘의 인수인 $1, $2, $3과 같은 이름을 가진 필드 변수가 각 입력 라인에 사용될 수 있다.
또 C 언어와 유사한 프린팅, 제어 연산자도 가지고 있다.

awk의 사용에는 두가지 방법이 있다.
한가지 방법은 다음 형식으로 타이프하는 것이다. 

# awk program filename
> program: 명령어들로 이루어짐 
> filename: awk가 작용할 파일의 명칭

# awk -f file filename
> file: 프로그램 명령어들을 포함하고 있는 파일의 명칭

프로그램은 하나 또는 그 이상의 프로그램 라인들로 이루어진다.
프로그램 라인은 일반적으로 패턴과 작용으로 이루어진다.

/rotate/ {print}
> 패턴은 rotate(단순한 문자열 패턴은 /들로 둘러싸임)
> 작용은 print이다.

이것을 사용하면,
awk 프로그램은 문자열 rotate를 포함하고 있는 라인들을 발견하고 그것들을 프린트한다.

그것은 grep rotate filename을 사용하는 것과 같다. 
필드들은 공백들에 의해 분리된 문자열들이다. 
awk 프로그램은 필드에 대한 레이블 시스템을 가지고 있다.
$1은 첫 번째 필드이고 $2은 두 번째 필드이다. 
$0은 특수한 의미를 갖는바, 그것은 전체 라인을 나타낸다. 

# 패턴의 의미
---------------------------------------------------------------------------------------------
/fish/ 문자열 fish를 포함하고 있는 라인
$1 - /fish/ 첫번째 필드가 문자열 fish를 포함하고 있는 라인
$3 - /fish/ 세번째 " "
$1! - /fish/ 첫번째 필드가 문자열 fish를 포함하고 있지 않은 라인
---------------------------------------------------------------------------------------------

# 작용의 의미
---------------------------------------------------------------------------------------------
{print $2} 두번째 필드만을 프린트하라
{print $4,$2} 네번째 필드의 내용을 프린트한 다음 두번째 필드의 내용을 프린트하라
{print $2,$2+$4} 두번째 필드를 프린트한 다음 두번째 필드와 네번째 필드의 합을 프린트하라
{s=$2+$4; print s} 두번째와 네번째 필드를 추가한 다음, 그 합을 프린트하라
---------------------------------------------------------------------------------------------

패턴에서의 ~와 !사용에 주목하라.
~는 우측에 있는 패턴이 좌측에 있는 필드에 포함된다는 것을 의미한다.
!~ 조합은 우측의 패턴이 좌측의 필드에 포함되지 않음을 의미한다.
{ }작용들을 세미콜론으로 분리시킴으로써 하나 이상의 작용들을 포함시킴 수 있다.

몇가지 이러한 개념들을 사용하는 간단한 예를 고찰해보자.
파일 sales는 여섯 열의 정보를 가지고 있다.
첫번째 열은 품목 명칭, 
두번째 열은 품목의 판매가격,
그리고 다음의 네 열들은 품목에 대한 분기별 판매수이다.

# vi sales
carts 29.99 45 13 55 22
corks 0.02 30 20 25 93
doors 49.99 40 15 20 25
geese 15.00 2 8 1 128
nighties 50.00 11 23 15 82

우리는 두 열을 추가하려 한다.
품목합계 그리고 현금 판매 합계.
다음과 같은 addup이라는 파일을 작성한다.

# vi addup
{total=$3+$4+$5+$6;print $0, total, total*$2}

이 작용은 ;에 의해 분리된 두 부분들을 가지고 있다.
첫 부분은 판매수를 합하고 영리하게도 합계를 total이라 부른다.
두번째 부분은 원래의 라인($0)을 프린트하고,
그 뒤에 합계를,
그 다음에는 total*$2를 프린트하는데, 이것은 합계x두번째 열을 의미한다.

# awk -f addup sales
carts 29.99 45 13 55 22 135 4040.64
corks 0.02 30 20 25 93 93 3.36
doors 49.99 40 15 20 25 100 4999
geese 15.00 2 8 1 128 139 2085
nighties 50.00 11 23 15 82 131 6550


2. awk 입력 라인을 읽는 방법
표준 입력이나 파일로부터 읽혀지는 각 라인은 공백문자로 구분된 필드를 가지고 있는 것으로 간주된다.
-F(field)선택자 뒤에 임의의 문자를 입력하면 필드 구분자가 그 문자로 변경된다.
예를 들어 :(콜론)을 구분자로 사용하려면 다음과 같이 입력한다.

# awk -F: -f prog files 

3. awk의 패턴과 연산
awk가 읽어들이는 라인과 필드들에 대한 작업은 패턴-연산의 쌍으로 정의되며,
이쌍은 다음과 같은 형식을 갖는다.

pattern {action} 

연산 부분을 중괄호로 둘러쌈으로써 패턴과 구분한다.
연산 부분이 생략되면 그 라인이 프린트된다.
일반적으로 사용되는 연산에는 print가 있으며 이 연산은 인수를 표준 출력에 출력한다.
다음연산은 입력 필드 개의 순서를 바꾸어 출력한다.
{ print $2, $1} 
# vi in.file 
hello goodbye again 
111 222 
thirty forty 

# vi awk.prog1 
{print $2, $1}

# awk -f awk.prog1 in.file
goodbye hello 
222 111
forty thirty

위의 예에서 print의 인수는 콤마로 구분되었으며,
이로 인해 출력 데이터 사이에 현재의 필드 구분자가 삽입되었다.
콤마가 생략되면 $1과 $2가 연속하여 출력된다.
예를 들어 다음의 awk 프로그램은
# vi awk.prog2 
/hello/ {print $2, $1}
# awk -f awk.prog2 in.file
> 입력 파일 내에서 패턴 /hello/과 일치하는 라인은 1개뿐이기 goodbye hello 때문에 그 라인에 대해서만 지정된 연산인 print가 실행되었다.
# vi awk.prog3
/hello/ {print $2, $1}
/thirty/ {print $1, $2, "and more"}
# awk -f awk.prog3 in.file
> print명령어의 인수가 따옴표로 둘러싸여 제공되었으며 그 문자열이 goodbye hello 출력에 표시되었다.
thirty forty and more
# vi awk.prog4
/hello/||/111/ {print "htt", $1, $2}
# awk -f awk.prog4 in.file
> ||연산자는 2개의 정규식 중 하나만 일치하면 지정된 연산을 실행하며,
hit hello goodbye &&연산자는 2개의 정규식이 모두 일치애햐 지정 연산을 실행한다.
hit 111 222 !연산자는 정규식이 일치하지 않아야 지정된 연산을 실행하며 정규식 앞에 기술된다.
# vi awk.prog5
/^[Hh1]/ {print "htt", $0}
# awk -f awk.prog5 in.file
> $0을 사용했기 때문에 입력 라인 전체가 출력되었음
hit hello goodbye again Hh1으로 시작하는 line을 출력
hit 111 222
# vi awk.prog6
/hello/ { 
print $2 
print "another" 
print $1 
}
# awk -f awk.prog6 in.file
> 패턴 /hello/와 일치하는 첫번째 입력 라인만이 연산의 대상이 됨
goodbye
another
hello

4. awk를 이용한 숫자 연산
awk의 산술 연산이 bc의 산술 연산과 다른 점은 awk는 입력 파일 내의 라인 중 일부를 선택하는 패턴 부분을 사용할 수 있다는 것이다.
예를 들어 awk의 내장 함수인 length는 문자열로 취급되는 입력 필드의 길이를 뱐환하며 숫자 변수는 숫자로 취급되는 필드의 값을 할당받을 수 있다.
# vi awk.prog7
{
s += $2
print $2, "length=" length($2), "s=" s
}
# awk -f awk.prog7 in.file
> 숫자로 변환될수 없는 문자열은 값이 0이 된다.
goodbye length=7 s=0 문자열 thirty가 그 예로서, 숫자로 변환될수 없다.
그러나 문자열 222 length=3 s=222 222는 숫자로 올바르게 변환되었다.
또한 s=0과 같은 형식으로 변수에 forth length=5 s=222 값을 할당할 수 있다.
다음은 awk변수의 올바른 예이다.
s
S
SS
S1
qwerty[42]
변수를 사용하기 전에 선언하거나 초기화시킬 필요는 없다.
awk가 자체적으로 변수를 초기화시키며 필요에 따라 그 변수를 문자열이나 숫자를 기억시킬수 있다.
# vi awk.prog8
/hello/ {
SSS=34
print "SSS is", SSS
SSS=hello
print "SSS is", SSS
}
# awk -f awk.prog8 in.file
> 이와 같은 자동적인 변수 형식 변환은 변수의 사용을 수월하게 한다.
SSS is 34
SSS is hello

5. 처리를 시작하고 끝내기 위한 특수 패턴
정규식 패턴 외에도 2개의 특수 패턴으로 BEGIN과 END가 사용된다.
BEGIN은 첫 번째 입력 라인을 읽기 전에 awk프로그램의 선두에서 실행되며 END는 마지막 입력 라인이 처리된 후 프로그램의 제일 끝에서 실행된다. 
BEGIN은 주로 변수 초기화 등의 작업에 사용되며 END는 마지막 계산을 하고 출력을 요약하는 작업에 사용된다.
BEGIN이나 END가 없어도 되나 필요한 경우 포함시킬 수 있다.
예를 들어 다음 프로그램은 여러 개 숫자의 평균값을 출력한다.
BEGIN {
print "Beginning to process the input data ..."
}
{
s += $1
n++
}
END {
print "mean of these",n,"data items is", s/n
}
메시지를 프린트하는 BEGIN과 관련된 연산은 프로그램의 선두에서 실행되며, 그 후에 각 입력라인이 읽혀진다.
패턴이 생략되었기 때문에 모든 입력 라인에 대해 연산이 실행되었다.
첫 번째 필드를 변수 s에 더하고 1을 증가시키며 마지막의 END패턴은 모든 입력이 처리된 후 실행된다.
이 END 패턴에서는 계산의 최종 결과를 출력하고 있다.

?