본문 바로가기

Development/Linux

AWK 정리

키워드
$[no]   : 공백문자를 기준으로 몇 번째 토큰인지를 나타내는 변수
print    : 표준 출력
BEGIN : 초기 변수 설정 등을 이 섹션에서 정의한다. 
ex) # awk 'BEGIN{ a=b;print "this is begin";}
END    : 모든 연산이 끝난 후 Finalize 하는 루틴. 
ex) # END{print "result is [" result "]"};
{ }       : BEGIN과 END 사이에 Keyword 없이 존재하는 중괄호는 awk 실행 본문에 해당된다.


내부변수
FS 필드 구분자 - Fields Seperator
RS 레코드 구분자 - Records Seperator
NF 현재 레코드의 필드수(Number of Fields)
NR 현재 파일에서 레코드 넘버(Number of Records)
FNR 입력파일이 여러개인 경우에 현재 파일에서의 NR을 표시한다.
OFS 출력시의 FS(Output Fields Seperator). 이 값을 변경하게 되면, 출력시의 FS 가 바뀌게 된다.
ORS 출력시의 RS(Output Records Seperator). 이 값을 변경하게 되면, 출력시의 RS 가 바뀌게 된다.


Awk 실행 파일의 작성
#!/bin/awk
# 실행 파일의 서두에 위의 선언이 나옴으로서 awk 형식의 처리가 가능해진다.
#

실행 예
awk [옵션] '스크립트' [-v 변수=값] [파일(들)]
awk [옵션] -f 스크립트 파일 [-v 변수=값] [파일(들)]
cf) 편집 스크립트 파일의 사용법
ed : ed -s(script) sourcefile < scriptfile
sed : sed -f(file) scriptfile sourcefile > outputfile
awk : awk -f(file) scriptfile sourcefile > outputfile 

실행 옵션
  • -Fc : field separator 지정
    • c는 필드 사이를 구분하는 구분자이다
    • 직접 지정하지 않으면 공백을 기준으로 한다
    • 시스템 변수 FS를 지정하는 것과 같은 효과를 지닌다
  • -v 변수 = 값
    • 스크립트를 실행하기 전에 미리 변수를 지정하여 준다
    • $를 쓰지 않고 변수 이름만 쓰면 된다. C에서 #define처럼 생각하면 될 것이다.
  • -f 스크립트 파일
    • 스크립트를 파일에서 가져온다
    • -f 옵션을 여러번 사용하여 여러개의 스크립트 파일을 동시에 불러와 지정한 파일에 적용할 수 있다 

  • 스크립트
  • 패턴 { 동작 }
    • 커맨드 라인에서는 패턴, 동작 전체를 단일 따옴표로 묶는다
    • 패턴만 있는 경우 : 패턴과 일치하는 레코드(라인)를 화면에 출력한다
    • 동작만 있는 경우 : 모든 레코드(라인)가 동작의 대상이 된다 

  • 패턴
    • /정규표현식/ sed가 지원하지 않는 +, ?, |, ( ) 등의 메타문자도 지원한다 또한 ^, $를 각 필드의 처음과 끝을 의미하도록 사용할 수도 있다
    • 비교연산 숫자 기준, 알파벳 기준 모두 사용 가능하다
    • 패턴 매칭 연산 ~ : 일치하는 부분을 나타낸다 !~ : 일치하지 않는 부분을 나타낸다
    • BEGIN 첫 번째 레코드가 읽혀지기 전에 어떤 동작을 정의하여 사용하고 싶을 때 사용한다
    • END 마지막 레코드가 모두 읽혀진 후 어떤 동작을 정의하여 실행하고 싶을 때 사용한다 

  • 동작
  • 동작은 모두 { }로 둘러싸야 한다
  • 예제
    • good이라는 문자열을 포함하는 모든 레코드를 출력할 때 /good/
    • 각 레코드의 첫 번째 필드를 출력할 때 { print $1 }
    • good이라는 문자열을 포함하는 레코드의 첫 번째 필드를 출력할 때 /good/ { print $1 }
    • 두 개 이상의 필드를 가지는 레코드를 전부 출력할 때(비교연산) NF > 2
    • 한 라인(\n)을 필드로, 빈 라인("")을 레코드로 구분할 때 BEGIN { FS = "\n" ; RS = ""}
    • 첫 번째 필드가 good와 일치하는 레코드에 대해 세 번째 필드를 먼저 출력하고 두 번째 필드를 나중에 출력하고 싶을 때 $1 ~ /good/ { print $3 , $2 }
    • good이라는 문자열이 몇 개나 들어가 있는지 계산하여 마지막 부분에서 출력하고 싶을 때 /good/ { ++x } END { print x }
    • 두 번째 필드를 모두 합하고 마지막 부분에서 두 번째 필드의 총합계를 출력하고 싶을 때 { total += $2 } END { print "Total of $2: " , total }
    • 레코드의 길이가 20자 이하인 것을 출력하고 싶을 때 length($0) < 20
    • 네 개의 필드를 가지며 good이라는 단어로 시작하는 모든 레코드를 출력하고 싶을 때 NF == 4 && /^good/
    • 빈줄을 제외한 모든 줄을 화면에 출력한다 NF > 0 

  • Awk 연산자
  • 산술 : =, +=, -=, *=, /=, %= 조건 : ? : 논리 : ||, &&, ! 패턴 : ~, !~
  • 비교 : <, <=, >, >=, !=,== 증감 : ++, -- 필드참조 : $

  • 제어문(C 와 동일)
  • break
  • continue
  • do {실행} while (조건)
  • exit
  • for (관계형 배열의 요소) {실행}
  • 펄의 foreach와 같다
  • if (조건) {실행} else {실행}
  • return
  • while 

  • awk command
  • 문자열 연산
    • gsub(reg,s) 입력 문자열의 전반에 걸쳐 정규표현식 r을 문자열 s로 대치한다.
    • gsub(reg,s1,s2) 문자열 s2에서 정규표현식 r을 s1으로 대치한다.
    • index(s1,s2) s1에서 s2의 위치를 넘겨준다. 만약 없다면 0을 넘겨준다.
    • length(arg) 인자의 길이를 넘겨준다.
    • match(s,r) 문자열 s에서 정규표현식 r과 매칭되는 부분의 위치를 넘겨준다.
    • split(string,array[,seperator]) 구분자를 기준으로(지정하지 않으면 공백 기준)해서 지정한 문자열을 배열로 만든다 배열[1], 배열[2], .......
    • sub(r,s), sub(r,s1,s2) gsub과 동일하다. 단지 정규표현식과 일치하는 문자열이 여러 개라도 처음 문자열만 대치된다
    • substr(s,m) 문자열 s에서 m번째 위치에서 끝까지의 문자를 리턴한다
    • substr(s,m,n) 문자열 s에서 m번째 위치에서 n번째까지의 문자를 리턴한다
    • tolower(str)
    • toupper(str) 

  • 수치 연산
    • atan2(x,y) y/x의 arctangent값을 라디안 단위로 넘겨준다
    • cos(x)
    • exp(arg)
    • int(arg)
    • log(arg)
    • rand() 0과 1사이의 난수를 발생한다
    • sin(x)
    • sqrt(arg)
    • srand(expr) 인자를 가지고 난수를 발생시킨다. 인자가 주어지지 않으면 시간을 가지고 난수를 발생시킨다. 

  • 입출력/프로세스
    • close(filename) 지정한 파일을 닫는다
    • close(cmd) 지정한 명령어 파이프를 닫는다
    • delete array[element] 지정한 배열 요소를 지운다
    • getline() 다음 레코드를 읽어 들인다
    • getline[variable] [< "filename"] 파일에서 읽어들인다
    • next 다음 레코드(라인)을 입력받는다 getline()과 유사하지만 /패턴/동작을 새롭게 시작한다 getline()은 다음 라인을 읽기만 한다
    • print [args] ![> "filename"] 인자를 출력한다
    • printf "format" [,expressions] ![> "filename"] 형식에 맞춰 출력한다
    • sprintf (format [,expressions]) printf와 마찬가지로 사용하는데 값을 리턴하기만 하고 출력은 하지 않는다.
    • system(command) 시스템 내부 명령어를 실행한다 

  • 용례
  • awk ' BEGIN { for (i = 1;i<=7,i++) print int(101*rand()) }' 화면에 1이상 100이하의 난수 일곱 개를 출력한다
  • ls -l file1 file2 file3 | awk ' { x += $5 } ; END { print "Total bytes : " x } ' 파일들의 크기를 모두 합하여 총 바이트 수를 표시한다
  • awk ' END { print NR } ' filename 지정한 파일의 라인이 몇 개인지를 표시한다
  • awk ' NR % 2 == 0 ' 지정한 파일의 짝수번째의 라인만을 출력해 준다