SRE/Linux Basics

awk

게임이 더 좋아 2022. 12. 7. 15:33
반응형
728x170

정의

 

AWK는 패턴 스캐닝언어로서 1977년에 Alfred Aho, Peter Weinberger, Brain Kerninghan에 의해 만들어진 language

뒷글자를 따서 AWK 로 지음

파일 수정이 용이하며 데이터베이스를 검색하고 변형하는데도 유용함

데이터 프로세싱, 리포트 작성, 간단한 데이터 베이스 구축등에 많이 응용함

 

파일의 각 라인에서 필드(field)를 인식할 수 있는 패턴 매칭 기능으로 조작하기 위함

파일로부터 레코드(record)를 선택하고, 선택된 레코드에 포함된 값을 조작하거나 데이터화하는 것을 목적

 

awk는 입력된 라인들의 데이터를 공백 또는 탭을 기준으로 분리해서 $1부터 각각의 필드로 분리해서 인식함

 

레코드와 필드라는 용어가 쓰임

레코드 = 해당 라인, row

필드 = 칼럼,col ($1, $2, $3, ...)

 

 

 

기본 포맷

 

awk [OPTION...] 'pattern { action }' [FILE | ARGUMENTS...]

 

pattern과 action이 모두 생략 가능하기 때문에 아래와 같은 형식도 쓰임

 

awk ['pattern'] file

=> action을 생략하는 경우 print라는 action이 default

awk '[action]' file

=> pattern을 생략하는 경우 모든 레코드에 대해 적용

 

 

 

 

 

예를 들면

 
# pattern 생략
$ awk '{ print }' ./file.txt      # file.txt의 모든 레코드 출력

# action 생략
$ awk '/p/' ./file.txt            # file.txt에서 p를 포함하는 레코드 출력

더 좋은 예를 들면

이런 계산을 할 수도 있다.

이런 파일을 만들고

1번째 필드와 2번째 필드를 곱한 값을 출력하는 것이다.

 

위에서 알 수 있듯이 필드를 공백(white space)으로 구분함

 

해석해보자면

:라는 구분자로 필드를 나눌 것이고

linux라는 패턴에 대해서 매칭을 시키고

1번 필드에 대한 print를 하겠다.

라는 말이다.

 

 

 


내부 변수

 

 

 

내장 함수

 

 함수  설명 
 gsub(r, s)  입력 문자열 전부에 걸쳐 정규식 표현 r을 문자열 s로 치환
 gsub(r, s1, s2)  입력 문자열 s2 에서 정규식 표현 r을 문자열 s1 으로 치환
 index(s1, s2)  s1에서 s2의 위치를 넘겨준다. 없다면 0
 length(arg)  인자의 길이를 넘겨줌
 match(s, r)  문자열 s에서 정규식 표현 r과 매칭 되는 부분의 위치를 넘겨줌.
 split(string, array[, seperator])  구분자를 기준으로(기본:공백)해서 지정한 문자열을 배열로 만듬
 sub(r, s) , sub(r, s1, s2)  gsub 와 동일
정규식 표현과 일치하는 문자열이 여러 개라도 처음 한 문자열만 치환
 substr(s, m)  문자열 s 에서 m번째 위치에서 끝까지 문자열을 넘겨줌
 substr(s, m, n)  문자열 s 에서 m번째부터 n번째까지 문자열을 넘겨줌
 tolower(string)  대문자를 소문자로 바꿈
 toupper(string)  소문자를 대문자로 바꿈
atan2(x, y)  아크 탄젠트(역탄젠트) 값
cos(x)  cos 값
exp(x)  (자연 상수)e^x
int(x)  정수형으로 반환
log(x)  로그
rand()  0에서 1까지 랜점
sin(x)  sin 값
sqrt(x)  제곱근
srand(expr)  인자를 가진 난수(없으면 시간을 가지고 난수 발생)
close(filename)  지정한 파일을 닫음
close(cmd)  지정한 명령어 파이프를 닫음
delete array[element]  지정한 배열 요소를 지움
getline()  다음 레코드를 읽음
getline [variable] [< "filename"]  파일에서 읽음
next  다음 레코드를 입력 받음
print [args] [> "filename"]  인자를 출력
printf "format" [,exp] [> "filename"]  형식에 맞춰 인자를 출력
sprintf(format [,exp])  printf와 마찬가지로 사용되지만 값을 반환만 하고 출력은 하지 않음
system(cmd)  시스템 내부 명령어를 실행

 

 

 

 

 

 


 

 

 

 

 

유의사항

 

  • awk program의 command 문장은 single quotes(' ') 또는 double quotes(" ")로 둘러싸여 있음
  • Input의 각 라인(Line)이 원하는 pattern과 일치하면, action 부분이 실행
  • action 없이 pattern만 있는 경우, 원하는 pattern을 찾으면 각 Input 라인을 그대로 출력
  • pattern 없이 action만 있는 경우, Input의 각 라인에 대해 action을 실행

 

 

 

용도

 

  • 텍스트 파일의 전체 내용 출력
  • 파일의 특정 필드만 출력
  • 특정 필드에 문자열을 추가해서 출력
  • 패턴이 포함된 레코드 출력
  • 특정 필드에 연산 수행 결과 출력
  • 필드 값 비교에 따라 레코드 출력

 

 

 


Option

 

옵션 설명
-u 버퍼를 사용하지 않고 출력
-F{d}

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


필드 구분자를 예로 설명하면

아래와 같은 식으로 쓸 수 있음

 

-F'[ :\t]' 다중 필드구분자 ':'와 tab을 필드구분자로 사용

 

 

 

 

 


 

Action

 

액션은 {}로 둘러싸인 문장이며 세미콜론(;)으로 구분

패턴은 액션 앞에 위치함

액션은 간단한 문장 또는 복잡한 문장들의 그룹으로 만들 수 있음

 

awk '/test/{print "Hello, "$1""}awkfile
패턴 액션 실행파일

 

 

awk -f

위 명령어를 이용하여 awk 명령들을 파일에 저장하고 파일에 입력된 명령을 사용하여 다른 파일을 처리할 수 있음

awk -f [awk명령파일] [awk명령을 적용할 텍스트파일]

 

 
vi awkcommand
{print "안녕하세요! " $1"님"}
{print $1, $2, $3, $4}
  
awk -f awkcommand /etc/passwd

 

 

 


 

awk와 같이 쓰는 정규 표현식

 

pattern 부분에 정규 표현식를 넣어서 라인을 매칭이 가능함

^ 문자열의 시작과 매칭
$ 끝과 매칭
. 문자 한 개와 매칭
* 문자가 없거나 그 이상 과 매칭
+ 하나의 문자 또는 그 이상 과 매칭
- 문자가 없거나 하나와 매칭
& 검색된 문자열로 대체 할 때 사용
[swiftTFT:ABC] 셋 중 하나의 문자와 매칭
[^ABC] 셋 중 매칭 되는 문자 없음
[swiftTFT:A-Z] 해당 범위 내 매칭 되는 문자가 있음
A|B A또는B 문자 매칭

 

 

 


연산자 및 표현식

 

match 연산자

match연산자는 하나의 레코드 또는 필드 안에서 표현식과 매칭되는 것이 있는지 검사하는 연산자

~ 일치하는 부분

!~ 일치하지 않는 부분

 
$awk '$1 ~ /admin[1-9]/' pw  
admin1    x    500    500    test    /test    /bin/csh

비교연산자

<, <=, ==, !=, >=, >

 
$awk '$3 == 500' pw
admin1    x    500    500    test    /test    /bin/csh

 

조건표현식

$awk '{max=($3 == $4) ? $1 : $2; print max}' pw

 

산술연산자

+-*/%^

 

 

논리연산자

&& || !

 

 

 

 

 

 


 

BEGIN  -  END

 

패턴에 맞는 입력을 식별하면 입력 데이터에 대한 처리가 진행되기 전 BEGIN에 정의된 액션을 실행함

모든 레코드(라인)에 대한 처리가 끝난 후 END에 정의된 액션을 실행함

 

일반적으로 아래의 형태를 가짐

  1. 시작(BEGIN) : 입력 데이터를 실행하기에 적합한 형태로 바꾸어주는 단계(전처리하는 부분)
  2. 실행(Routine) : BEGIN에서 잘 처리된(정규화된) 데이터를 실제 루틴으로 처리하는 것, 여기서 데이터는 처리 루틴에 따라 처리가 되며, 입력 값이 루틴을 거쳐 결과 값이 출력
  3. 끝(END) : BEGIN와 마찬가지로, 데이터가 처리된 후에 처리해야 할 내용들을 담고 있음,  결과의 추가 출력들을 예로 들 수 있음

 

위의 형태를 하고자 할 때 BEGIN - END 패턴을 쓴다.

 

 

예시

 

 

빌트인 내장변수(OFS, RS, FS등)들의 값을 변경하기 위해, 사용자정의형 변수들의 초기값을 할당하기 위해, 출력의 한부분으로서 헤더 또는 타이틀을 프린트하기위해 자주 사용

 
awk 'BEGIN{FS=":"; OFS="\t"; ORS="\n\n"}{print $1,$2,$3}' filename

#입력파일이 처리되기 전에 필드분리자(FS)가 콜론(:)으로 설정되고, 출력 필드 분리자(OFS)가 탭으로 설정되며, 출력 레코드 분리자(ORS)가 두개의 newline으로 설정됨

 

입력의 모든 라인이 처리되고 실행되며 뒤에 파일 명을 출력

awk 'END{print "records is " NR }' test.txt

 

스크립트를 정의해서 실행하게 된다면 아래와 같이 이용

sum.awk
#!/bin/awk
#
# This Program is for Summing of exam_result.
#
  
# BEGIN : 프로그램 시작 처리
BEGIN {
    sum = 0;
    print "총점 출력 프로그램";
}
  
# ROUTINE : 프로그램 본문
{
    sum += $2;
}
  
# END : 프로그램 마무리 처리
END {
    print "합계 : " sum;
    average = sum / NR;
    print "평균 : " average;
}



############################################
score.txt
100
80
99
66
87
99

 

 

 

간단한 실행을 하고자 하면 아래처럼 이용도 가능

 

awk 'BEGIN {print "TITLE : Field value 1,2"} {print $1,$2} END {print "Have Finished"} test.txt

 

시작 전에 실행할 action에 대해 설명해주고

action을 실행하고

action이 끝났음을 알려주자

 

 

 

 


 

제어문

 

실제로 제어문을 한 줄로 쓰는 것은 가독성이 엄청나게 떨어진다.

그래서 awk는 개행 문법을 지원함

→ 커맨드 라인 한 줄 이상으로 작성하여 하나의 커맨드 실행 가능

=> 아래와 같이 실행 가능

# if문
if ( condition ) { Routine } else { Routine }
  
# for문
for ( init ; condition ; re ) { Routine }
  
# while문
while (condition) { Routine }
  
# do ~ while문
do { Routine } while (condition)
  
# 반목문 제어
break
continue
return
  
# 프로그램 제어
next
exit

 

 

#if
$ awk '{
    total=$3+$4+$5;
    avg=total/3;
     
    if ( avg >= 90 )
        grade="A";
    else if ( avg >= 80)
        grade ="B";
    else if (avg >= 70)
        grade ="C";
    else
        grade="D";
  
    print $0, grade;
 }' filename

#for
$ awk '{
for(i=0;i<2;i++)
 print( "for loop :" i "\t" $1, $2, $3)
}' filename


#while
$ awk '{i=1;
while(i<=NF) {
print NF, $1; i++}
}' filename

break문이나 continue 문과 같은 제어도 가능

 
$ awk '{
    for(x=3; x<=NF; x++)
        if($x<0) {print "Bottomed out!"; break}
  
    for(x=3; x<=NF; x++)
        if($x==0) {print "Get next item"; continue}
 }' filename

 

프로세스 제어도 가능

next : 입력 파일로부터 다음 입력행을 가져와서 awk 스크립트의 맨 처음부터 다시 실행

exit : awk 프로그램을 종료시킬 때 사용. exit 문은 레코드의 처리를 중단시키지만, END 문 너머로 건너뛰지 않음

 
# 1번째 필드가 Peter를 포함하면 이 행을 지나고 다음행을 입력받고, 스크립트는 처음부터 다시 실행
$ awk '{
    if($1~/Peter/) {next}
    else {print}
 }' filename


# 첫 번째 레코드만 출력하고 실행 중지
$ awk '{ print $0; exit }' file.txt

 

 

 


 

 

예시

 

 
#/etc/passwd파일에서 계정명(ID)만 출력

#1. 파일의 형태를 보기
cat /etc/passwd

#2. 계정명 : 패스워드부분 : UID : GID : 코멘트 : 홈디렉토리 : 기본사용쉘 필드로 나눠짐
root:x:0:0:root:/root:/bin/bash

#3. $1 $2 $3 $4 $5 $6 $7

#4. 원하는 필드 출력
cat /etc/passwd | awk -F: '{print $1}'

root


###########################################################################################

# /home을 home 디렉토리로 사용하는 모든 사용자 정보 출력하기(명령어 파일로 만들어서 한 번에 실행하기)

#커맨드 해석
grep home passwd | awk -F: '{print "grep "$1" /home/moonly/passwd"}' > test.sh

#grep home passwd passwd파일내에서 home이라는 문자를 가진 행들은 모두 출력
#awk -F: '{print "grep "$1" /home/moonly/passwd"}' grep :기준으로 첫번째문자 /home/moonly/passwd => 출력
#> test.sh test.sh파일로 문자열 저장

#test.sh 파일은 아래와 같이 작성됨

grep wnn /home/test/passwd
grep mysql /home/test/passwd
grep pcpuser /home/test/passwd

여기서
#!/bin/bash => 쉘스크립트 실행을 위해 추가

chmod 700 test.sh

#./test.sh 실행
#test.sh파일에 저장되어있던 grep명령이 실행됨



###################################################################################################

#각 행 번호 출력 (NR 내장 변수 이용)

$ cat test.csv
1,2,3
4,5,6
7,8,9
$ cat test.csv | awk -F, '{print NR " " $0;}'
1 1,2,3
2 4,5,6
3 7,8,9
$ awk_example]$ cat test.csv | awk -F, '{print NR-1 " " $0;}' # 0부터 시작
0 1,2,3
1 4,5,6
2 7,8,9



#######################################################################################################

#패턴 매칭

$ awk '/pp/' ./file.txt                             # "pp" 가 포함된 레코드만 유효
$ awk '/[2-3]0/' ./file.txt                         # 20, 30 이 포함된 레코드만 유효
$ awk '$1 == 2 { print $2 }' ./file.txt             # 첫 번째 필드가 2인 레코드의 두 번째 필드 출력
$ awk '$3 > 70 { print $0 }' ./file.txt             # 세 번째 필드가 70보다 큰 레코드 출력
$ awk '$3 == 30 && $4 ==40 { print $2 }' file.txt   # 세 번째 필드가 30이고 네 번째 필드가 40인 레코드의 두 번째 필드 출력
$ cat c.txt | awk '$1=="a"' str.txt                 # 특정 레코드만 출력
$ cat c.txt | awk '$1!="a"' str.txt                 # 특정 레코드 제외 출력
$ cat c.txt | awk '$2~/^e/' str.txt                 # 패턴비교. $2필드가 문자e 로 시작하는 레코드만 출력

 

 

 

 

 


참고링크

 

 

https://recipes4dev.tistory.com/171

https://inpa.tistory.com/entry/LINUX-%F0%9F%93%9A-awk-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AC%B8%EB%B2%95-%EB%A7%88%EC%8A%A4%ED%84%B0-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

 

 

728x90
반응형
그리드형

'SRE > Linux Basics' 카테고리의 다른 글

cp  (0) 2022.12.18
cd  (0) 2022.12.18
Proxy  (0) 2022.12.07
find  (0) 2022.12.07
실시간 모니터링  (0) 2022.12.07