지금까지 다룬 주요 커맨드들은 다음과 같습니다.
curl : 웹페이지 소스를 내려받는데 주로 쓰이는 커맨드
sed : 주로 텍스트 라인별로 패턴을 찾거나 찾은 패턴을 다른 텍스트로 바꾸는데 쓰는 커맨드
grep : 텍스트에서 원하는 텍스트를 포함하는 라인만 출력하는 커맨드
sed로도 grep의 일부 기능을 수행할 수도 있기는 합니다만, 두 커맨드의 장단점이 있기 때문에 둘다 다 많이 쓰는 커맨드입니다.
이번에 다룰 커맨드는 awk입니다. 1977년에 처음 개발한 사람들의 이름의 첫자를 따서 (Alfred Aho, Peter Weinberger, and Brian Kernighan) 커맨드의 이름이 만들어졌습니다.
sed와 grep과는 달리 awk는 좀 더 프로그래밍 언어에 가깝습니다. 프로그래밍 문법은 거의 C언어와 비슷하지만, 어려운 문법은 별로 없는 편입니다. 따라서 이미 C언어나, java, javascript, 또는 php와 같은 프로그래밍 언어를 이미 할 줄 아는 사람은 awk 커맨드를 비교적 쉽게 배울 수 있습니다.
반대로 C, java, javascript, 또는 php를 배울 생각이 있는 사람은 awk를 먼저 배우는 것도 좋은 방법입니다. 이들 프로그래밍 언어 문법의 기본을 배울 수 있기 때문입니다.
이제 기본적인 awk사용방법을 알아보겠습니다.
아주 간단한 학생 성적 데이터가 있다고 가정해 보겠습니다. 학생은 김철수 이영희 박영수 최순희 이렇게 네명이 있고, 과목은 국어 영어 수학 과학 이렇게 네 과목이 있다고 해보겠습니다. 선생님은 이들 성적을 scores.txt라는 텍스트 파일로 만들었습니다. 그 내용을 다음과 같습니다.
학생이름 국어 영어 수학 과학
김철수 85 75 80 80
이영희 90 85 85 90
박영수 60 55 45 50
최순희 100 95 95 95
이 내용을 scores.txt에 저장하려면 먼저 cat > scores.txt를 실행한 다음 위의 내용을 복사해 붙이고 Ctrl+d 키를 누루면 됩니다.
파일이 준비됬으면 다음 커맨드를 실행해 보겠습니다.
cat scores.txt | awk '{print $1}'
학생이름
김철수
이영희
박영수
최순희
cat scores.txt는 원래 scores.txt에 저장된 내용을 화면에 출력합니다. 그런데 이 커맨드 다음에 | (파이프)기호가 나오면 화면에 출력하는 대신 | 다음에 오는 커맨드가 키보드로 입력받는 것처럼 읽어들일 수 있게 넘깁니다. awk커맨드 다음의 작은 따옴표로 묶여있는 중괄호안에 있는 내용이 awk가 실행하는 코드의 내용입니다.
awk는 라인별로 텍스트를 읽어들일때마다 공백으로 분리된 내용을 순서대로 \$1 \$2 \$3 \$4 …에 저장합니다. 따라서 맨 위 첫째줄의 경우는 \$1에 ‘학생이름’이라는 텍스트가 저장되고, \$2에는 ‘국어’가, \$3에는 ‘영어’가, \$4에는 ‘수학’이, \$5에는 ‘과학’이 저장됩니다. (csv 파일처럼 쉼표로 분리된 내용도 순서대로 저장하기도 하는데 그렇게 할려면 awk 커맨드의 옵션을 사용해야합니다. 이 부분은 곧 다룰 예정입니다.)
작은 따옴표로 묶여있는 중괄호({})안의 코드 print \$1는 매 라인마다 첫번째로 분리된 내용을 화면에 출력하라는 코드입니다. 따라서 첫번째 공백 전에 있는 텍스트를 화면에 출력합니다. 파이프(|)를 쓰지 않고 위의 커맨드를 아래와 같은 형식으로도 쓸 수 있습니다.
awk '{print $1}' < scores.txt
커맨드 맨 뒤에 < scores.txt 를 붙이면 < 기호 다음에 적은 파일을 읽어들여 키보드로 입력받는 것처럼 읽어들일 수 있게 합니다. < 를 빼고 써도 같은 결과가 나옵니다. 이 경우는 awk 커맨드에서 중괄호 코드 다음에 오는 텍스트가 입력파일을 의미하기 때문입니다.
awk '{print $1}' scores.txt
각 줄의 세번째 내용을 출력하려면 \$1 대신 \$3을 쓰면 됩니다.
awk '{print $3}' scores.txt
영어
75
85
55
95
첫번째 내용과 세번째 내용을 출력하려면 \$1과 \$3을 쓰고 그 사이에 쉼표를 붙여주면 됩니다. 두 내용 사이에는 자동으로 공백 하나가 들어가 둘을 분리해 출력합니다.
awk '{print $1, $3}' scores.txt
학생이름 영어
김철수 75
이영희 85
박영수 55
최순희 95
각 줄의 모든 내용은 $0에 저장됩니다. 따라서 print \$0 라고 치면 파일내용 그대로 출력합니다.
awk '{print $0}' scores.txt
학생이름 국어 영어 수학 과학
김철수 85 75 80 80
이영희 90 85 85 90
박영수 60 55 45 50
최순희 100 95 95 95
그런데 맨 첫째줄의 내용을 출력하고 싶지 않습니다. 이때 사용하는 변수가 NR입니다. 각줄에서 코드를 실행할때마다 NR에는 몇번째 줄인지를 나타내는 숫자가 미리 저장되어 있습니다. 첫번째 줄일때는 1이 저장되고, 두번째 줄일때는 2이 저장되는 식입니다. 이 NR 변수를 체크해서 프린트할지 안할지를 결정하면 됩니다.
첫번째 줄에서 출력을 안하고 다른줄에서는 모두 출력을 하려면, NR이 1이 아닐때 출력을 하면 됩니다. 이걸 코드로 표현하면 if (NR != 1) print \$0 가 됩니다. !=는 양쪽 값이 같지 않을때는 참이고 같으면 거짓입니다. 따라서 if (NR != 1) 이라고 쓰면 NR에 저장된 값이 1이 아닐때만 다시 말해 첫째줄이 아닐때만 그다음에오는 코드를 실행합니다. 결국 if (NR != 1) print \$0 는 첫째줄만 빼고 다른 모든줄의 전체 내용을 출력합니다.
awk '{if (NR != 1) print $0}' scores.txt
김철수 85 75 80 80
이영희 90 85 85 90
박영수 60 55 45 50
최순희 100 95 95 95
만약에 이름까지 가리고 싶으면 print \$0 대신 print \$2,\$3,\$4,\$5라고 쓰면 됩니다.
awk '{if (NR != 1) print $2,$3,$4,$5}' scores.txt
85 75 80 80
90 85 85 90
60 55 45 50
100 95 95 95
따옴표로 묶여있으면 그 안의 내용은 여러줄에 걸쳐서 입력해도 하나의 텍스트로 인식합니다. 이를 이용하면 위의 코드를 아래와 같이 좀 더 이해하기 쉽게 그리고 분석하기 쉽게 쓸 수 있습니다.
cat scores.txt | awk ' { if (NR != 1) print $2,$3,$4,$5 }'