[Linux] 리눅스 명령어 - awkLinux2022. 2. 22. 20:16
Table of Contents
728x90
✅ awk 명령어
- 파일로부터 레코드를 생성하고 레코드에 포함된 값을 조작하거나 데이터화 하기위한 명령어이다.
- 파일의 각 라인에서 필드를 인식할 수 있는 패턴 매칭 기능을 가지고 이 필드들을 자유자재로 조작하기 위해 만들어졌다.
- awk가 실행하는 기능(패턴 매칭과 액션 실행)들이 프로그래밍 언어로 작성되었다.
- 주 기능
- 텍스트 파일의 전체 내용 출력.
- 파일의 특정 필드만 출력.
- 특정 필드에 문자열을 추가해서 출력.
- 패턴이 포함된 레코드 출력.
- 특정 필드에 연산 수행 결과 출력.
- 필드 값 비교에 따라 레코드 출력.
- awk는 기본적으로 입력 데이터를 라인(line) 단위의 레코드(Record)로 인식한다. 그리고 각 레코드에 들어있는 텍스트는 공백문자(space, tab)로 구분된 필드들로 분류된다. 이렇게 식별된 레코드 및 필드의 값들은 awk 프로그램에 의해 패턴 매칭 및 다양한 액션의 파라미터로 사용된다.
✅ awk 프로그램의 구조 및 실행
✅ awk 프로그램의 구조
(1)
awk ' pattern {action}
pattern {action}
.
.
.
' filenames <----------------- 입력 파일
===========================================
(2)
awk -f parttern-action-file filenames <---- 입력 파일
# awk 실행 action을 가진 프로그램 file
✅ 패턴
BEGIN | 특정 명령을 실행하기 전에 먼저 실행시킨다. |
END | 특정 명령을 실행한 후 제시되는 문장을 실행시킨다. |
/정규표현식/ | 정규표현식의 패턴을 포함하는 라인에서 문장을 실행시킨다. |
패턴1 && 패턴2 | 패턴1과 패턴2를 동시에 만족시킬 때 문장을 실행시킨다. |
패턴1 || 패턴2 | 패턴1이나 패턴2 중 하나만 만족시켜도 문장을 실행시킨다. |
! 패턴 | 패턴과 일치하지 않을 경우 문장을 실행시킨다. |
✅ awk의 내부 변수
FILENAME | 현재 처리되고 있는 파일 이름 |
FS | 필드 구분자 |
RS | 레코드 구분자 |
NF | 현재 레코드에서의 필드 수 |
NR | 현재 파일에서 전체 레코드 수 |
OFS | 출력시의 필드 구분자 |
ORS | 출력시의 레코드 구분자 |
✅ awk 사용 예시
# cat data
hong 28se 011-222-2222 seoul
park 34se 017-333-3333 kyunggi
im 23se 019-444-4444 chungnam
son 49se 016-555-5555 us
gil 19se 018-666-6666 korea
jang 21se 011-7777-7777 japan
lee 16se 016-8888-8888 china
sa 45se 017-9999-9999 canada
hwang 32se 015-555-5555 kwangju
# $1, $3 필드를 출력하라는 말이다. 만약 전체 필드를 출력하려면 $0 인자를 사용한다.
# awk '{print $1,$3}' data
hong 011-222-2222
park 017-333-3333
im 019-444-4444
son 016-555-5555
gil 018-666-6666
jang 011-7777-7777
lee 016-8888-8888
sa 017-9999-9999
hwang 015-555-5555
Q) 25세 이상인 사람의 이름과 나이를 출력하라
# awk '$2 > 25 {print $1,$2}' data
hong 28se
park 34se
son 49se
sa 45se
hwang 32se
# 정확한 데이터 추출을 위해서는 se 라는 문자를 제거해줄 필요가 있다.
# sed 's/se / /g' data | awk '$2 > 25 {print $1,$2}'
hong 28
park 34
son 49
sa 45
hwang 32
# 앞뒤로 문자열을 붙여주면 문장으로 표현할 수 있다.
# sed 's/se / /g' data | awk '$2 > 25 {print $1"씨는 ",$2"세 입니다."}'
hong씨는 28세 입니다.
park씨는 34세 입니다.
son씨는 49세 입니다.
sa씨는 45세 입니다.
hwang씨는 32세 입니다.
# 파일에 se 문자열을 치환하는 명령줄을 저장해서 사용할 수도 있다.
# cat > sedfile1
s/se / /g
# cat > awkfile1
$2 > 25 {print $1"씨는 ",$2"세 입니다"}
# sed -f sedfile1 data | awk -f awkfile1
hong씨는 28세 입니다
park씨는 34세 입니다
son씨는 49세 입니다
sa씨는 45세 입니다
hwang씨는 32세 입니다
Q) 나이의 평균을 구하는 프로그램을 구현해보라
# cat sedfile1
s/se / /g
# cat > awkfile2
# 특정 명령을 실행하기 전에 먼저 실행시킨다.
BEGIN {
sum = 0; # sum 변수에 0을 저장
line = 0; # line 변수에 0을 저장
}
{
sum += $2; # sum 변수에 각 행마다 두번째 필드 값을 저장한다.
line ++; # 라인 값을 1씩 상승시킨다.
}
END { # 특정 명령을 실행한 후 제시되는 문장을 실행시킨다.
average = sum / line; # 평균을 구한다.
print "나이의 평균 : "average"세";
}
# sed -f sedfile1 data | awk -f awkfile2
나이의 평균 : 29.6667세
Q) /etc/passwd 1000 uid 이상의 사용자는 일반유저이다. 일반 유저 정보만 출력하라 (단 계정명과 uid, 사용자 홈 디렉토리 형태로 출력하시오)
[root@localhost ~]# awk -F : '$3 >= 1000{print $1,$3,$6}' /etc/passwd
nobody 65534 /
user 1000 /home/user
test1 1001 /home/test1
Q) 디스크 영역은 /dev로 시작된다. 40프로가 넘는 사용률을 가진 디스크를 출력하라
[root@localhost ~]# df -hTP | sed 's/%//g' | awk '$1 ~ /^\/dev/ && $6 >= 40 {print$1, $6"%", $7}'
/dev/nvme0n1p1 45% /boot
/dev/sr0 100% /run/media/root/CentOS-8-3-2011-x86_64-dvd
awk를 이용하여 실무에서 사용할 수 있는 실전으로 응용해보자
lastb.txt 파일의 내용
user ssh:notty 192.168.110.200 Mon Oct 5 17:25 - 17:25 (00:00)
user ssh:notty 192.168.110.200 Mon Oct 5 17:13 - 17:13 (00:00)
user ssh:notty 192.168.110.200 Mon Oct 5 17:13 - 17:13 (00:00)
user ssh:notty 192.168.110.200 Mon Oct 5 17:13 - 17:13 (00:00)
user ssh:notty 192.168.110.200 Mon Oct 5 17:09 - 17:09 (00:00)
user ssh:notty 192.168.110.136 Mon Oct 5 17:08 - 17:08 (00:00)
user ssh:notty 192.168.110.136 Mon Oct 5 17:07 - 17:07 (00:00)
userhat ssh:notty 192.168.110.136 Mon Oct 5 16:27 - 16:27 (00:00)
userhat ssh:notty 192.168.110.136 Mon Oct 5 16:27 - 16:27 (00:00)
userhat ssh:notty 192.168.110.100 Mon Oct 5 16:27 - 16:27 (00:00)
userhat ssh:notty 192.168.110.100 Mon Oct 5 16:26 - 16:26 (00:00)
userhat ssh:notty 192.168.110.100 Mon Oct 5 16:26 - 16:26 (00:00)
user ssh:notty 192.168.110.110 Mon Oct 5 17:13 - 17:13 (00:00)
user ssh:notty 192.168.110.110 Mon Oct 5 17:09 - 17:09 (00:00)
user ssh:notty 192.168.110.110 Mon Oct 5 17:08 - 17:08 (00:00)
user ssh:notty 192.168.110.110 Mon Oct 5 17:07 - 17:07 (00:00)
userman ssh:notty 192.168.110.110 Mon Oct 5 16:26 - 16:26 (00:00)
userman ssh:notty 192.168.110.110 Mon Oct 5 16:25 - 16:25 (00:00)
userman ssh:notty 192.168.110.110 Mon Oct 5 16:25 - 16:25 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
userman ssh:notty 192.168.110.136 Mon Oct 5 16:25 - 16:25 (00:00)
userman ssh:notty 192.168.110.136 Mon Oct 5 16:25 - 16:25 (00:00)
userman ssh:notty 192.168.110.136 Mon Oct 5 16:25 - 16:25 (00:00)
userman ssh:notty 192.168.110.136 Mon Oct 5 16:25 - 16:25 (00:00)
userman ssh:notty 192.168.110.136 Mon Oct 5 16:24 - 16:24 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
userhat ssh:notty 192.168.110.136 Mon Oct 5 16:26 - 16:26 (00:00)
userhat ssh:notty 192.168.110.136 Mon Oct 5 16:26 - 16:26 (00:00)
test ssh:notty localhost Mon Oct 5 16:23 - 16:23 (00:00)
root :0 :0 Mon Oct 5 11:02 - 11:02 (00:00)
btmp begins Mon Oct 5 11:02:02 2020
이 때 10번 이상 접속한 유저를 출력하기 위해서는 다음과 같은 명령줄을 이용하면 된다.
awk '$3 ~ /^[0-9]/{print $3}' lastb.txt | sort | uniq -c | awk '$1>=10{print "10회 이상 접속 시도 ip = "$2}'
10회 이상 접속 시도 ip = 192.168.110.136
# 3번째 필드가 숫자이면 그 필드를 출력한다.
# awk '$3 ~ /^[0-9]/{print $3}' lastb.txt
# 정렬 후 중복을 제거한 뒤 카운트 계산을 한다.
# uniq 사용에 앞서 반드시 sort를 해줘야 한다.
# sort | uniq -c
# 선행 명령줄을 실행한 결과 중 첫번째 필드가 10이상인 것을 출력한다.
# awk '$1>=10{print "10회 이상 접속 시도 ip = "$2}'
✅ awk 예제 실습
① 입력화일의 이름은 students
② 이 파일의 각 라인은 3 개의 필드로 구성(학생 성명, 학과명, 나이)
③ 각 필드는 공백에 의해서 분리(공백을 필드 분리자로 간주함.)
< awk 는 각 라인에서 필드를 추출해 내는 데 필드 분리자(field separator)를 사용, 필드 분리자는 보통 하나 이상의 공백 문자이다.>
$ cat students
John,P Physics 20
Rick,L Mechanical 21
Jack,T electrical 23
Larry,M Chemical 22
Phil,R Electrical 21
Mike,T mechanical 22
Paul,R Chemical 23
John,T Chemical 23
Tony,N Chemical 22
James,R Electrical 21
1) 식(expression)에 맞는 field 프린트
$ awk '$3 > 22 {print $1}' students
# students 파일의 세번째 필드가 22보다 큰 행의 첫번째 필드를 출력한다는 의미
Jack,T
Paul,R
John,T
2) if 문을 사용하여 조건에 맞는 line 분리하기 (각 파일에 저장)
step 1 : if 문을 사용하는 프로그램을 awkprog1 이라는 파일로 만든다.
$ cat awkprog1
{ if ($1 ~ /^J/) printf "%s₩n", $0 > "Jfile"
if ($1 ~ /^P/) printf "%s₩n", $0 > "Pfile"}
# 입력으로 Jfile이 들어오면 첫번째 필드의 값이 J로 시작하는 모든 행의 전체 필드값을 출력
# 입력으로 Pfile이 들어오면 첫번째 필드의 값이 P로 시작하는 모든 행의 전체 필드값을 출력
step 2 : students 입력화일에 awkpog1 프로그램 화일을 적용한다.
$ awk -f awkprog1 students
step 3 : 결과 보기
$ cat Jfile
John,P Physics 20
Jack,T electrical 23
John,T Chemical 23
James,R Electrical 21
$ cat Pfile
Phil,R Electrical 21
Paul,R Chemical 23
3) 평균값 구하기
<프로그램 awkprog2, awkprog3>
$ cat awkprog2
{sum += $3} # 세번째 필드의 값을 sum에 계속 더한다.
END {printf "The average of the ages is %.2f₩n", sum/NR}
# NR : 현재 파일에서 전체 레코드 수
$ cat awkprog3
{sum += $3
++no} # no를 1씩 증가시킨다.
END {printf "The average of the ages is %.2f₩n", sum/no}
<결 과>
$ awk -f awkprog3 students
The average of the ages is 21.80
4) while 과 do 문을 이용하여 평균값 구하기
<프로그램 awkprog4>
$ cat awkprog4
{if (NF > 0) { # NF : 현재 레코드에서 필드 수
sum = 0
n = 1
while (n <= NF) {
sum = sum + $n
n = n+1
}
printf "Average is %d₩n", sum/NF
}
else
print}
<예 제>
% awk -f awkprog4 test
Average is 17
Average is 3
Average is 25
Average is 0
참고
728x90
'Linux' 카테고리의 다른 글
[Linux] 리눅스 명령어 - 시스템 디스크 명령어 (0) | 2022.02.24 |
---|---|
[Linux] 하드링크와 심볼릭링크 (0) | 2022.02.24 |
[Linux] 리눅스 명령어 - sort, sed (0) | 2022.02.22 |
[Linux] 리눅스 명령어 - 파일 입출력 명령어(grep) (0) | 2022.02.22 |
[Linux] 리눅스 명령어 - 파일 입출력 명령어(cut, paste, diff) (0) | 2022.02.22 |
@TTOII :: 뭉게뭉게 클라우드
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!