오래전 이야기/Server

awk 사용법

리눅스 엔지니어였던 2009. 4. 7. 18:26
1. awk의 사용법
  awk [옵션] '스크립트' [변수=값] [파일(들)]
  or
  awk [옵션] -f 스크립트 파일 [변수=값] [파일(들)]

  ' '안에는 직접 원하는 동작을 정의하거나 -f를 이용하여 스크립트
  파일을 따로 불어올수도 있다. 스크립트 파일이 여러개 있다면 -f
  옵션을 여러번 사용해서 여러개의 스크립트 파일을 동시에 불러와
  지정한 파일에 적용하는것도 가능하다.

  변수는 sheel 환경변수($foobar)가 될수도 있고 명령어 대치('command')
  가 될수도 있지만 실제로 사용할 수 있으려면 입력을 읽어들인 후에 가능하.
  즉 기본적으로 한라인 단위로 입력을 받아 처리하게 되는데 awk에서는
  BEGIN이라고 직접 명시해줄 수도 있다. BEGIN등의 awk가 사용하는 키워드에 대해서는
  뒤에 자세하기 살펴보게 도니다.

2. 옵션
  -Fc : c를 각 필드 사이를 구분하는 구분자로 사용한다. 직접 지정하지
        않으면 공백을 기준으로 삼게 된다. 이것은 awk 시스템 변쇼ㅜ인 FS
      를 지정하는것과 같은 효과를 지니며, $1, $2 $3등으로 각 필드를 지정
      할수 있고, $0는 레크도 전체를 가리킨다.
      필드와 레코드의 개념을 잡기 위해 옐르 들어보자. /etc/passwd는 각 필드
      사이가 ';'으로 구분되어 있다. 이 /etc/passwd의 첫번째, 두번째 필드만을
      화면에 출력하기 위해서는 다음과 같이 하면 된다.

      [r00t@netro r00t]$
      [r00t@netro r00t]$ awk -F: '{print $1; print $2; print $0}' /etc/passwd
      root
      x
      root:x:0:0:System Administrator,Cad,NO,NO:/root:/bin/bash
      bin
      x
      bin:x:1:1:bin:/bin:
      daemon
      x
      daemon:x:2:2:daemon:/sbin:
      adm
      x
      adm:x:3:4:adm:/var/adm:
      lp
      x
      lp:x:4:7:lp:/var/spool/lpd:

       ....... 상략 ........

  -v 변수=값
    스크립트를 실행하기 전에 미리 변수를 지정하여 준다. 첫번째 예에서
    awk스크립트를 직접 커맨드라인 상에서 모두 지정해 주었는데, -f 옵션
    을 이용하해서 어떻게 스크립트 파일을 만들어낼 수 있는지 살펴보자

    다음과 같은 내용의 파일을 만들어 awk1이라는 이름으로  저장하고

    {print $1; print $2; print $0}

    다음과 같이 실행하여도 똑같은 결과를 얻게 된다. 위의 오션 설명에서 -Fc
    는 awk시스텝 변수인 FS를 지정하는것과 똑같다고 했으므로 다음과 같이 하면
    된다.

    [r00t@netro r00t]$ awk -f awk1 FS: /etc/passwd

3. awk 스크립트
  awk스크립트는 패턴과 동작을 ㅗ구성되엉 ㅣㅆ다.

  패턴 {동작}

  동작은 해당 패턴과 일치하는 필드나 레코드에 대해서 어떤 처리를 해줄것인지
  결정하는 것이다. 첫번째 예처럼 만약 패턴을 지정하지 않는 경우에는 모든
  레코드에 대해서 지정한 동작이 영향을 미치게 되며 동작이 지정되지
  않으면 지정한 패턴과 일치하는 레코드가 화면에 ㅊ출력된다.

  패턴
    여기서 사용 가능한 패턴은 다음과 같다.
    
    . /정규표현식/
    . 비교연산
    . 패턴 매칭 연산
    . BEGIN
    . END

    ./정규표현식/
      정규 표현식은 sed에서와 마찬가지 형태로 사용할 수 있으며 sed가
      지원하지 않는 +, ?, |, ()등의 메타캐릭터들도 지원하고 있다. 또
      라인의 처음과 끝을 의미하는 ^와 $를 각 필드의 처음과 끝을의미하
      도록 사용할 수도있다.

    .비교연산
      예를 들어 $2 > $1이라고 한다면 두번째 필드가 첫번째 필드보다 큰
      레코드를 모두 지정하는 방법이 되겠는데 숫자 기준, 알파벳 기준모두
      사용가능하다. 뒤에 연산자 부분에서 자세히 다룬다.

    .패턴 매칭 연산
      ~는 일치하는 부분을 나타내고, !~는 일치하지 않는 부분을 나타낸다.
      역시 연산자 부분에서 자세히 다루겠다.

    .BEGIN
      첫번째 레코드가 읽혀지기 전에 어ㄸ너 동작을 정의하여 실행하고
      싶을때 사용한다.

    .END
      마지막 레코드가 모두 읽힌 후 어떤 동작을 정의하여 실행하고 싶을
      때 사용한다. 여기서의 패턴은 BEGIN과 END를 제외하고는 모두
      ||(or), &&(and), !(not)과 함께 어울려서 사용할 수도 있으며
      "패턴, 패턴"형식으로 사용하면 범위를 지정하여 줄수도 있다.

  동작
    동작은 한개 또는 그 이상의 명령어와 함수, 변수값 지정등이 될 수 있다.
    여러개의 동작을 지정할 때는 한 라인에 몰아서 써줄 경우 ';'으로
    구분하고 각각의 동작을 서로 다른 라인에 적어줄 때느ㅜㄴ ';'이 필요없다.
    또한 동작은 모두 {}로 둘러싸 주어야 한다.

    <example>
    . 각레코드의 첫번째 필들 출력
    { print $1 }
    . r00t라는 문자열을 포함하는 모든 레코드를 출력할때
    /r00t/
    . r00t라는 문자영ㄹ을 포함하는 레코드의 첫번째 필드를 출력할때
    /r00t/{print $1}
    . 두개이상의 필드를 가지는 레코드를 전부 출력할때(비교연산)
    NF > 2
    . 한라인을 하나의 필드로 처리하고 아무것도 쓰여져 있지 않은 빈라인을
    기준으로 레코드를 구분할때
    BEGIN { FS = '\n'; RS = "" }
    . 첫번째 필드가 r00t와 일치하는 레코드에 대해서 세번재 필드를 먼저
    출력하고 두번째 필드를 나중에 출력하고 싶을때(패턴 매칭 연산)
    $1 ~ /r00t/ {print $3, $2}
    . r00t라는 문자열이 몇개나 들어가 있는지 계산하여 마지막 부분에서
    출력하고 싶을때
    /r00t/ {++x}
    END {print x}
    . 두번째 필들 모두 합하고 마지막 부분에서 두번째 필드의 총합을 출력하고
    싶을때
    {total += $2}
    END {print "colume total is", total}
    . 레코드의 길이가 20자 이하인것을 출력하고 싶을때
    length($0) < 20
    . 일곱개의 필드를 가지며 NAME:라는 단어로 시작하는 모든 레코들 출력하고
    싶을때
    NF == 7 && /^NAME:/

4. awk의 시스템 변수
  FILENAME : 현재 파일명
  FS : 입력 필드 구분(디폴트는 공백)
  NF : 현재 레코드의 필드 개수
  NR : 현재 레코드의 번호
  OFMT : 숫자에 대한 ㅊ출력 포멧(디폴트는 %.6g)
  OFS : 풀력 필드 구분(디폴트는 빈줄)
  ORS : 풀력 레코드 구분(디폴는 뉴라인(newline))
  RS : 입력 레코드 구분(디폴트는 뉴라인(newlinue))
  $0 : 입력 레코드
  $n : 입력 레코드의 n번째 필드
  ARGC : 커맨드라인의 인자 개수
  ARGV : 커맨드 라인 인자를 포함하는 배열
  ENVIRON : 환경 변수들을 모아둔 관계형 배열
  FNR : NR과 같다. 하지마 ㄴ 현재 파일에 적용된다는 점이 다르다
  RSTART : 지정한 매칭 연산을 만족하는 문자열의 맨 앞ㅂ분
  RLENGTH : 지정한 매칭 연산을 만족하는 문자열의 길이
  
5. awk의 연산자
  =, +=, -=, *=, /=, %=, ^= : c에서와 같다
  ?: -> 조건연산, 역시 C와 같다.
  || -> 논리연산 or
  && -> 논리연사 and
  !  -> 논리연사 not
  ~, !~ -> 매칭 연산, 지정한 표현과 매치될때, 매치되지 않을 때를 나타낸다.
  <, <=, >, >=, !=, == -> c와 같다, 비교연산자들
  +, -, *, /, %, ^ -> 더하기, 빽, 곱하기, 나누기, 남저ㅣ, 제곱
  ++, -- -> 증가, 감소 연산자
  $ -> 필드 참조

6. awk명령어 레퍼런스
  수치연산
    atan2 : atan2(y,x)
    cos : cos(x)
    exp : exp(arg)
    int : int(arg)
    log : log(arg)
    rand : rand()
    sin : sin(x)
    sqrt : sqrt(arg)
    srand : srand(expr)
  문자열 연산
    gsub : gsub(r, s[,t])
    index : index(str, substr)
    length : length(arg)
    match : match(s,r)
    split : split(string, array[, sep])
    sub : sub(r, s[,t])
    substr : substr(string, m[,n])
    tolower : tolower(str)
    toupper : toupper(str)
  제어문
    break
    continue
    do/while
    exit
    for
    if
    return
    while
  입출력/프로세서
    close : close(filename-expr)
    delete : delete array[element]
    getline : getline [var][<file]
    next : next
    print : print [args][destination]
    printf : printf format [, expression(s)][destination]
    sprintf : sprintf(format, [,expression(s)])
    system : system(command)


  이름순 구변!!

  atan2(y,x)
    y/x의 acrtangent값을 라디안 단위로 넘겨줌
  break
    while, for, do루프에서 탈출한다.
  close
    close(팡ㄹ명)
    close(명령ㅇ)
    지정한 파일이나 명령어 파이프를 닫는다

  contine
    while, for, do에서 다음 푸프로 넘어감

  cos(x)
    cos(x) : x의 코사인 값을 라디안 단위로 넘겨줌
  delete 배열(요소)
    지정한 배열의 요소를 지운다.
  do
    do
      .....
    while(조건)
    c에서의 do-while문과 같다.  
    
  exit
    END부분으로 넘어간다.
  exp
    exp(n)
    exponential n, e의 n승 값을 넘겨줌

  for
    for ([초기조건;[비교];[증감연사])

  for
    for (관계현 배열의 요소)

  getline
    getline[변수]ㅔ[<파일명] 또는 명령어 | getline [변수]
    현재 입력받은 레코드의 다음범 레코들를 받아 들인다.
    next와 비슷하다.

  gsub
    gsub(r, s[,t])
    정규표현식 r과 매치되는 문자열 t를 s로 대친한다. 만약
    t를 지정하지 않으면 $0라고 가정한다.

  if
    if (조건) ... [els ...]

  index
    index(문자열 A, 문자열 B)
    문자열 A에서 문자열B의 위치를 넘겨준다. 만약 없다면 0을 넘겨줌
  
  int
    int(인자)
    인자의 접수갑
    
  length
    length(이나)
    인자의 길이

  log
    log(인자)
    인자의 자련로그 값

  match
    match(s, r)
    문자열 s에서 정규표현식r과 매치되는 부분의 위치를 넘겨준다.

  next
    다음 레코들 이렵력 받는다, getline과 비슷하지만 패턴/동작 과정을
    새롭게 시작한다느넋이 차이가 있다.
  print
    print [인자][방향]
    인자를 출력한다. 만약 방향을 짖어하면 그쪽으로 출력한다.
    예들 들어 > foo bar라고 한다면 foobar라는 파일에 내용ㅇ르 저장하게 된다.

  printf
    C의 printf함수ㄱ와 거의 비슷 %s는 문자열, %d는 십진수, %n.mf는 실수 펴현
    방법으로 ..
    
    {printf "The sum total on line %s is %s\n", NR $1+$2}

  rand
    rand()
    0와 1사이의 남수를 발생, srand참고

  return
    값을 반환, C의 리턴문과 같다.

  sin
    sin(x)

  split
    split(문자열, 배열[, 구분자])
    구분자를 기준으로 (지정하지 않으면 공백 기준)해서 지정한 문자열을 배열로
    만든다.

  sprintf
    printf에서의 형식과 마찬가지로 사용하는데 값을 리턴하기만 하고 출력하지는
    않는다.

  sqrt

  srand
    srand(인자)
    인자를 지정하지 않으면 시간을 이용한다.

  sub
    sub(r, s[, t])
    정규 표현식 r와 매치되는 문자열 t를 s로 대친한다. gsub와 다른점은
    문자열 t에서의 r과 매치되는 부분이 여러개라 할지라도 처음 한개만
    대치한다는 것이다.

  substr
    substr(문자열, m[,n])
    m번째 위치에서부터 시작하여 n개까지의 문자를 지정한 문자열로 부터
    넘겨줌, n이 지정되지 않으면 m부터 끝까지

  system
    system(명령ㅇ)
    시스템 내부 명령어 실행

  tolower
    지정한 문자열의 모든 문자열의 대문자를 소문자로

  toupper
    소문자를 대문자로

  while
    while (조건) 명령

    지정한 조건을 만족하는 한 명령을 계속해서 실행

7. awk의 간단하 실행 예
  awk '{if (length($0) > max) max = length($0) } END {print max}' 파일명
  지정한 파일에서 가장 긴 라인의 글자 수를 나타냄

  expand 파일명 | awk '{if (x<length()) x= length() }
  END {print "maximum line length is " x}'
  
  awk 'length($0) > 80' 파일명
  지정한 파일에서 한 라인의 길이가 80칼럼을 넘어가는 것만 나타낸다

  awk 'NF > 0'파일명
  지정한 파일에서 아무것도 쓰여있지 않은 빈줄을 뺀 모든줄을 화면에 출력

  awk 'BEGIN { for (i=1; i<=7 ; i++) print int(101 * rand()) }'
  화면에 0이상 100이하의 난수 일곱 개를 출력

  ls -l 파일1 파일2 파일3 | awk '{x += $5};
  END {print "total bytes: " x }'

  ls -l file1 file2 file3 | awk '{x += $5}
  END {print "total K-Bytes: "(x+1024)/1024 }'

  awk -F: '{print $1}' /etc/passwd |sort

  awk 'END {print NR}' 파일
  -> wc -l 파일
  
  awk 'NR % 2 == 0' 파일

==========================
<출처 : https://netro.ajou.ac.kr/doc/zboard.php?id=linux&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=237 >