쉘 스크립트를 만들 때, 자주 사용하지만, 쉘 스크립트를 만들 일이 그다지 많지 않아, 쓸 때마다 찾아보는 awk라는 명령이 있습니다. 얼마 전에도 쉘 스크립트를 만들다가 사용법을 찾아본 김에 내용을 정리해 놓기로 했습니다.
awk 란?
awk는 unix 계열의 os에서 텍스트에서 패턴을 추출하거나, 가공하기 위해서 사용하는 명령입니다. 텍스트를 출력하는 명령과 연계하여 주로 사용하고, 출력을 전달받아서, 내용의 일부만 추출하는데 주로 사용합니다. awk는 1970년 벨 연구소에서 Alfred Aho, Peter Weinberger, Brian Kerninghan 세 사람이 만들었고, 세 사람의 이름 첫 글자를 따서 이름 지어졌다고 하며 오크라고 발음합니다.
사용법
사용하는 방법은 패턴과 동작 그리고 입력 파일을 파라미터로 줍니다. 대게 파일을 따로 만들지는 않고 이전 명령의 출력을 전달받아 입력으로 사용합니다.
awk 'pattern' filename
awk '{action}' filename
awk 'pattern {action}' filename
패턴에는 정규 표현식을 사용할 수 있고, 인자는 $0 모든 필드, $1 첫 번째 필드, $2는 두 번째같이 $숫자로 필드를 구분할 수 있습니다.
사용예시
예를 들어볼까요? 예제를 보면 더 이해하기 쉬울 거예요. 현재 폴더를 한번 볼까요?
root@84e5f6280ccb:~# ls -al
total 48
drwx------ 1 root root 4096 May 26 14:09 .
drwxr-xr-x 1 root root 4096 May 22 12:56 ..
-rw------- 1 root root 1188 May 26 15:06 .bash_history
-rw-r--r-- 1 root root 3106 Dec 5 14:39 .bashrc
drwx------ 3 root root 4096 May 26 13:53 .cache
drwx------ 2 root root 4096 May 26 14:09 .docker
-rw-r--r-- 1 root root 161 Dec 5 14:39 .profile
drwxr-xr-x 2 root root 4096 May 5 08:07 .ssh
-rw------- 1 root root 8032 May 26 13:55 .viminfo
-rwxr-xr-x 1 root root 3157 May 22 14:27 build.sh
drwxr-xr-x 2 root root 4096 May 26 13:55 golang
이중 12월에 만든 파일만 보고 싶다면 다음과 같이 사용할 수 있습니다.
root@84e5f6280ccb:~# ls -al | awk /Dec/'{ print $0 }'
-rw-r--r-- 1 root root 3106 Dec 5 14:39 .bashrc
-rw-r--r-- 1 root root 161 Dec 5 14:39 .profile
출력되는 행에 Dec가 포함된 것을 출력한 것인데, 좀 더 정확히는 필드를 지정해서 할 수도 있습니다.
root@84e5f6280ccb:~# ls -al | awk '$6 == "Dec" { print $0 }'
-rw-r--r-- 1 root root 3106 Dec 5 14:39 .bashrc
-rw-r--r-- 1 root root 161 Dec 5 14:39 .profile
필드에 출력되는 내용을 변경할 수도 있습니다.
가령 만든 날자를 모두 1일로 변경해서 출력할 수도 있습니다.
root@84e5f6280ccb:~# ls -al | awk '$7 = "1" { print $0 }'
total 48 1
drwx------ 1 root root 4096 May 1 14:09 .
drwxr-xr-x 1 root root 4096 May 1 12:56 ..
-rw------- 1 root root 1188 May 1 15:06 .bash_history
-rw-r--r-- 1 root root 3106 Dec 1 14:39 .bashrc
drwx------ 3 root root 4096 May 1 13:53 .cache
drwx------ 2 root root 4096 May 1 14:09 .docker
-rw-r--r-- 1 root root 161 Dec 1 14:39 .profile
drwxr-xr-x 2 root root 4096 May 1 08:07 .ssh
-rw------- 1 root root 8032 May 1 13:55 .viminfo
-rwxr-xr-x 1 root root 3157 May 1 14:27 build.sh
drwxr-xr-x 2 root root 4096 May 1 13:55 golang
그리고 무엇보다 제가 자주 사용하는 것은 현재 실행 중은 애플리케이션의 PID를 조회하는 거예요.
root@84e5f6280ccb:~# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:04 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 6 1 0 14:04 ? 00:00:00 sshd: root@pts/0
root 9 1 0 14:04 ? 00:00:00 sshd: root@notty
root 38 9 0 14:04 ? 00:00:00 /usr/lib/openssh/sftp-server
root 39 6 0 14:05 pts/0 00:00:00 -bash
root 146 39 0 14:26 pts/0 00:00:00 ps -ef
root@84e5f6280ccb:~# echo `ps -ef | grep 'sftp' | grep -v grep | awk '{print $2}' `
38
실행 중인 프로세스를 조회하고, 거기서 sftp가 포함된 것을 grep으로 찾아내서 2번째 필드인 PID만 출력했습니다.
grep으로 sftp가 들어간 행을 필터 하지 않고 awk에 패턴을 주어 필터 할 수도 있습니다.
root@84e5f6280ccb:~# echo `ps -ef| grep -v awk | awk '/sftp/{print $2}' `
38
가운데 grep은 awk 프로세스를 걸러내기 위함입니다. 그렇지 않으면 PID가 두 개 출력되게 됩니다.
awk 액션이 복잡해질 경우, 별도의 파일을 작성하여 실행하는 방법도 있으나, 그렇게 사용하기보다는 위에처럼 간단히 사용하는 경우가 대부분입니다. 그래서 요정도만 알아도 쉘 스크립트 작성하는 데는 무리가 없습니다. 패턴 또는 액션을 따옴표로 묶어준다는 것과 $0은 전체 $1은 첫 번째 같은 것만 기억해도 쉽게 사용하 실 수 있을 겁니다.