ps -ef | grep -v grep | grep -e jr2A -e BCDC2A2B | awk '{print "ps -efx | grep -v grep | grep " $2}' | sh
1 머리말 #
awk는 명령어를 사용하다보면, 의외로 자주쓰는데, 지금까지 얼추 맞춰서 쓰다가 문서는 찾았습니다만, 위키에 없어서 찾은것들을 정리해서 글을 씁니다. 공개되어있는 문서를 찾아서 했기에, 절대 창작문서가 아닙니다.
단지 내용정리일 뿐입니다.
우선적으로 내용을 옮겨놓기때문에 두서가 없을수도 있습니다.
조금 길어지다 보니.. 형식이 마구 틀어지고, 테이블 무서지고 있습니다... 그런데, 위키초보라서 잡기가 매우 힘들군요... 좀.. 도와주세요 ㅠ.ㅠ --maylinux
2 Awk 란? #
awk는 프로그램 툴이다. 이 툴은 상당히 배우기 쉽고, 사용하기가 편리하다. 왜 그럴까? awk는 기본적으로 데이터처리를 위한 상당히 잘 만들어진 프로그래밍 모델을 가지고 있다. 이 말은 돌려서 얘기한다면, 일반적인 프로그램을 짜기에는 불편하다는 얘기가 될수 있다. 즉 perl에서 지원하는 여러가지 API 함수를 이용한 프로그램이나, 복잡한 정규표현식을 처리하기에는 많은 어려움이 있다는 것이다. 즉, awk 는 awk 나름대로의 용도라는 것이 있다는 말이다. 물론 awk 가지고도 여러가지 복잡한 일반프로그래밍이 가능하지만, 솔직히 이러한 것을 처리할때에는 awk 보다는 다른 프로그램을 사용하는 것이 좋다.
일단 간단히 얘기하자면, awk는 데이터 양식의 문서나 또는 자료를 처리하여 다른 형태의 문서 또는 결과물을 출력하는데 쓰인다. 실제로 awk의 프로그램 동작 모델은 이것을 위해 아주 잘 만들어져 있다. 뭐, 잘 만들어져 있는지 아닌지는 다음의 글들을 읽어야 알겠지만, 일단은 그렇다는걸 기억해 두기 바란다.
3 awk의 구조(Model) #
awk는 위에서 언급한 바와 같이 데이터 처리를 위해 최적화 되어 있다고 했다. 그러면, 어떠한 모델이 데이터 처리에 적합한 것일까? 일단 아래의 내용을 보고 나서 계속 설명하겠다.
1. 시작(BEGIN) : 입력데이터를 실행하기에 적합한 형태로 바꾸어 주는 단계이다. 프로그램적인 말로는 preprocess라고 한다.
2. 실행(Routine) : ?시작 단계에서 잘 처리된(정규화된) 데이터를 실제 루틴으로 처리하는 것이다. 여기서 데이터는 처리 루틴에 따라 처리가 되며, 입력값이 루틴을 거쳐 결과값이 나오게 된다.
3. 끝(END) : ?시작 단계와 마찬가지로, 데이터가 처리된 후에 처리해야 할 내용들을 담고 있다. 결과의 추가 출력들을 예로 들수 있다.
4 awk 프로그램 #
4.1 일반적인 awk 의 용도 및 사용방법(Using Model) #
awk는 일반적으로 데이터 또는 유사 데이터양식의 파일 및 자료를 처리하는데 쓰인다. 예를 들어 통계 자료나, text 형식의 access(?MicroSoft), 실험식의 계산 결과 등을 통계를 낸다던지 비교 분석 한다던지 다른 형태의 문서(결과물)로 변환하는 등의 작업에 사용된다. 따라서 이러한 작업에 있어서 awk는 100%의 작업효율을 가져올수 있다. 물론 perl이나, 유사프로그램을 사용해도 좋지만, 특별하게 복잡한 구조를 가지지 않는다면, 굳이 "토끼 잡는데, 소잡는 칼을 쓸 이유는 없다"는 것이다. awk만으로 충분하며, 또한 sed나 다른 GNU 유틸을 병합하여 사용하는 것이 단일 perl 프로그램이나, 기타 데이터 처리 프로그래밍 언어를 사용하는 것보다 훨씬 낫기 때문이다.
개인적인 관점으로는 GNU 유틸들은 상당히 유연하고(flexible)하고, 간편하지만, 실제적으로 개개의 GNU 유틸로 작업을 하기에는 상당히 힘이 든다. 그러나, 이들 GNU 유틸들을 적절하게 조합하여 사용하면, 기존의 여타 프로그램들과 동등한 기능을 발휘하는 멋진 프로그램이 될수 있는 것이다.
그래서 보통의 작업은 awk 하나만 가지고, 모두 다 처리 할수가 없다. 하고자 하는 일의 일부분을 awk가 맡을수 있는 것이다. 보통의 일반적인 awk의 사용은 다음과 같은 단계를 거치게 된다.
egrep 및 grep 을 이용한 데이터 파일의 구조확인을 한다. 정규화가 가능한지를 확인하고, sed 로 테스트 해본다. awk가 처리할만큼 정규화가 되어 있다면, 바로 awk를 사용한다. sed로 정규화된 양식을 awk로 처리한다. 데이터의 양식 데이터는 일반적으로 Record와 Fields를 가진다. 일반적으로 한라인(한줄)이 1 record가 되고, Fields의 구분은 "□"(공백문자)를 구분자로 하게 된다. (레코드와 필드에 대해서 이해가 가지 않는 사람은 ?DataBase 에 대한 개요등을 참고 하기 바란다.)
일반적으로 awk가 처리 할수 있는 데이터의 형식은 다음과 같다.
■■■□■■■■□■■■□■■■□■■■■■■□■■■■
■■■■□■■□■■■■■■■□■■■■□■■□■■■■
■■□■■■■■■■■■□■■□■■□■■■■■■■■□■
위의 데이터는 아래의 형식으로 바뀌게 된다.
record1: ■■■ ■■■■ ■■■ ■■■ ■■■■■■ ■■■■
record2: ■■■■ ■■ ■■■■■■■ ■■■■ ■■ ■■■■
record3: ■■ ■■■■■■■■■ ■■ ■■ ■■■■■■■■ ■
Field 1 Field 2 Field 3 Field 4 Field 5 Field 6
$1 $2 $3 $4 $5 $6
( 위의 표가 잘 이해되지 않는다면, DB 입문서등을 읽어보도록 한다. )
각 라인이 한 레코드가 되며, 스페이스로 분리된 문자열이 Field(또는 Column)으로 나뉘게 된다. 실제로는 한 레코드가 한 라인과 일지 않을수도 있으며, Field 를 구분하는 것도 공백 문자가 아닐수도 있다. 자세한 내용은 다음의 예제를 보면서 이해를 할수 있을 것이다.
4.2 Example 1 - 간단한 awk 사용 #
# cat exam_result.dat
박종규 95점
이억운 98점
이훈강 99점
엄성기 100점
정영원 97점
박오근 98점
여기서 각 줄이 한 레코드가 된다. 그리고, "박종규 95점"이란 내용에서 "박종규", "95점"이란 문자열이 각각의 필드(항목)가 되는 것이다.
간단히 이름을 출력해 보기로 하자
# awk '{print $1}' exam_result.dat
박종규
이억운
이훈강
엄성기
정영원
박오근
print 명령은 간단히 처리중에 필요한 내용을 출력하는 함수이다. "$1"은 1st(첫번째) 필드를 지시한다. 마찬가지로 점수를 출력하려면, "$1" 대신에 "$2"를 입력하면 된다. 그러면, 라인의 전체 내용을 출력하려면 어떻게 해야하는가? "$0"를 사용하면, 라인의 전체 내용을 출력할수 있다.
이제 여기에서 시험친 사람들의 총점을 구하려고 한다. 어떻게 해야 할까? 일단 합계는 숫자만이 가능한데, 현재는 "95점", "98점"과 같이 "점"이라는 글자가 포함되어 있어, 필드로 구분해 내어도 계산이 불가능하다. 그러면, 일단 sed 프로그램을 사용해 "점"이라는 글자를 삭제하여 연산이 용이하도록 만들어보자.
sedscr의 내용
# cat sedscr
s/점$//
# sed -f sedscr exam_result.dat
박종규 95
이억운 98
이훈강 99
엄성기 100
정영원 97
박오근 98
자 이제 계산할수가 있을듯 하다. 그러면, 프로그램을 짜 보자.
# sed -f sedscr exam_result.dat | awk 'BEGIN{ sum = 0; print "총점 출력 프로그램"; } {sum += $2} END {print "합계 : " sum}'
총점 출력 프로그램
합계 : 587
위의 내용을 설명하도록 하면 다음과 같다.
BEGIN{ sum = 0; print "총점 출력 프로그램"; } 위에서 언급 awk 의 모델링에서 BEGIN 부분에 해당한다. 루틴이 돌아가기 이전에 필요한 작업을 이부분에 기재할수 있으며, 출력의 머릿말 등을 달아 둘수 있다. 합계를 내기위한 변수 sum을 지정하고, 그 값을 0 으로 초기화 하였다.
{sum += $2} 실제 프로그램 내용이다. 위에서 Routine(루틴)이라 설명한 곳이다. 이 부분은 한 필드마다 적용이 되며, 함수나 루틴을 사용하여 필요한 작업을 수행한다. 현재의
END {print "합계 : " sum} 위에서 언급한 END(마지막) 처리 부분이다. 모든 연산이 끝나고 난 다음 마지막 출력 양식이라든지 결과값을 출력한다. 현재 소스는 합계내역을 출력한다.
위의 소스는 알아보기 힘들기 때문에, awk 코드 부분을 파일로 저장하여 실행하는 방법을 써 보도록 하자.
아래의 내용으로 sum.awk 파일을 작성해 보자
# cat sum.awk
#!/bin/awk
#
# This Program is for Summing of exam_result.
#
# BEGIN : 프로그램 시작 처리
BEGIN {
sum = 0;
print "총점 출력 프로그램";
}
# ROUTINE : 프로그램 본문
{
sum += $2;
}
# END : 프로그램 마무리 처리
END {
print "합계 : " sum;
}
위에서 첫줄의 #!/bin/awk 는 앞으로의 내용들은 /bin/awk 프로그램을 사용해서 번역(처리)을 하겠다라는 지정 구문이다. 쉘스크립트의 "#!/bin/sh"와 같은 역할을 한다고 생각하면 될 것이다. 첫줄 이외에 "#" 으로 시작하는 문장들은 모두 주석이다. 프로그램의 설명이나, 함수, 루틴에 대한 설명을 적어둔다. 각 내용은 한줄이 끝날때마다 ";"(세미콜론)을 붙여서 분리를 한다.
자, 위의 awk 스크립트 파일로 실행을 해 보기로 하자.
# sed -f sedscr exam_result.dat | awk -f sum.awk
awk 스크립트 파일을 호출할때에는 "-f 파일이름" 옵션을 사용한다는 것을 기억해야 한다.
자, 그러면 이 프로그램에서 평균은 어떻게 구할수 있을까? 이미 눈치를 챈 사람들이 있을 것이다. sum.awk 파일을 수정해 보자.
# cat 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 / 6;
print "평균 : " average;
}
실행을 하면 아래와 같이 된다.
# sed -f sedscr exam_result.dat | awk -f sum.awk
총점 출력 프로그램
합계 : 587
평균 : 97.8333
4.3 awk의 내부변수 #
awk에는 awk 가 내부적으로 가지는 변수들이 있다. 이 변수들을 사용하여, 필드 및 레코드의 구분을 좀 더 다양하게 할수 있으며, 좀 더 flexible(유연한)프로그램을 짤수가 있다. 아래에 각 내부 변수들에 대해서 설명해 두었다.
FS : 필드 구분자 - Fields Seperator
RS : 레코드 구분자 - Records Seperator
NF : 현재 레코드의 필드수(Number of Fields)
NR : 현재 파일에서 레코드 넘버(Number of Records)
FNR : 입력파일이 여러개인 경우에 현재 파일에서의 NF를 표시한다.
OFS : 출력시의 FS( Output Fields Seperator ). 이 값을 변경하게 되면, 출력시의 FS 가 바뀌게 된다.
ORS : 출력시의 RS( Output Records Seperator ). 이 값을 변경하게 되면, 출력시의 RS 가 바뀌게 된다.
4.4 Example 2 - awk 프로그램 응용 #
여기서 FS 와 RS 에 대한 부가 설명을 해야할것 같다. 일반적으로 데이터는 보통 한 라인이 한 레코드에 해당하고, 빈칸이나, 탭등이 필드를 구분한다. 그러나, 실제로 데이터파일에서 이런식으로 처리가 되지 않는 경우가 있으며, 굳이 데이터 파일만이 아니라, 다른 형식의 파일도 처리하기 때문에 FS, RS는 임의 설정이 가능해야 한다. 예를 들어 다음과 같은 명함 목록 파일을 보자.
# cat cards.dat
박종규
리눅스넷(주)
부산 광역시 연제구 연산동 한충 빌딩 000호
051-831-0000
김진억
이즈시스템
서울시 서초구 방배2동 400-0 0층
02-3000-0000
위의 데이터 파일은 한 한줄이 한 레코드가 되지 않는다는걸 알수 있다. 한 레코드는 한줄이 비워진 줄, 즉 정규식으로 표현하자면 "\n\n" 으로 구분되어 있으며, 레코드내에서 필드의 구분은 개행("\n")으로 구분된다. 따라서, 위의 데이터에서 이름과 전화번호만을 출력하고 싶다면, 다음과 같이 awk 스크립트를 작성할수 있다.
# cat block.awk
#!/bin/awk
BEGIN {
RS = "\n\n";
FS = "\n";
}
{
print $1, $NF;
}
위의 스크립트에서 BEGIN 부분에서 RS와 FS를 임으로 "\n\n" 과 "\n"으로 변경하였다. 또한 루틴부분에서는 첫번째 필드($1)와 마지막 필드($NF)의 내용을 출력하도록 하였다. NF현재 레코드에서 필드의 숫자를 나타낸다. 여기서 인자값을 호출하는 "$" 붙이게 되면, 마지막 필드값이 출력이 되는 것이다.
5 또다른 요약 페이지 #
awk는 직접 사용자로부터 입력을 받거나 아니면 지정한 파일을 가공하여 표준 출력한다. 표준 출력을 리다이렉션할 수 있다
사용법
awk ?옵션 '스크립트' ?-v 변수=값 ?파일(들)
awk ?옵션 -f 스크립트 파일 ?-v 변수=값 ?파일(들)
cf) 편집 스크립트 파일의 사용법
ed : ed -s(script) sourcefile < scriptfile
sed : sed -f(file) scriptfile sourcefile > outputfile
awk : awk -f(file) scriptfile sourcefile > outputfile
옵션
-Fc : field separator 지정
c는 필드 사이를 구분하는 구분자이다
직접 지정하지 않으면 공백을 기준으로 한다
시스템 변수 FS를 지정하는 것과 같은 효과를 지닌다
-v 변수 = 값
스크립트를 실행하기 전에 미리 변수를 지정하여 준다
-f 스크립트 파일
스크립트를 파일에서 가져온다
-f 옵션을 여러번 사용하여 여러개의 스크립트 파일을 동시에 불러와 지정한 파일에 적용할 수 있다
스크립트
패턴 { 동작 }
커맨드 라인에서는 패턴, 동작 전체를 단일 따옴표로 묶는다
패턴만 있는 경우 : 패턴과 일치하는 레코드(라인)를 화면에 출력한다
동작만 있는 경우 : 모든 레코드(라인)가 동작의 대상이 된다
패턴
/정규표현식/
sed가 지원하지 않는 +, ?, |, ( ) 등의 메타문자도 지원한다 또한 ^, $를 각 필드의 처음과 끝을 의미하도록 사용할 수도 있다
비교연산
숫자 기준, 알파벳 기준 모두 사용 가능하다
패턴 매칭 연산
~ : 일치하는 부분을 나타낸다 !~ : 일치하지 않는 부분을 나타낸다
BEGIN
첫 번째 레코드가 읽혀지기 전에 어떤 동작을 정의하여 사용하고 싶을 때 사용한다
END
마지막 레코드가 모두 읽혀진 후 어떤 동작을 정의하여 실행하고 싶을 때 사용한다
동작
동작은 모두 { }로 둘러싸야 한다
예제
good이라는 문자열을 포함하는 모든 레코드를 출력할 때
/good/
각 레코드의 첫 번째 필드를 출력할 때
{ print $1 }
good이라는 문자열을 포함하는 레코드의 첫 번째 필드를 출력할 때
/good/ { print $1 }
두 개 이상의 필드를 가지는 레코드를 전부 출력할 때(비교연산)
NF > 2
한 라인(\n)을 필드로, 빈 라인("")을 레코드로 구분할 때
BEGIN { FS = "\n" ; RS = ""}
첫 번째 필드가 good와 일치하는 레코드에 대해 세 번째 필드를 먼저 출력하고 두 번째 필드를 나중에 출력하고 싶을 때
$1 ~ /good/ { print $3 , $2 }
good이라는 문자열이 몇 개나 들어가 있는지 계산하여 마지막 부분에서 출력하고 싶을 때
/good/ { ++x } END { print x }
두 번째 필드를 모두 합하고 마지막 부분에서 두 번째 필드의 총합계를 출력하고 싶을 때
{ total += $2 } END { print "Total of $2: " , total }
레코드의 길이가 20자 이하인 것을 출력하고 싶을 때
length($0) < 20
네 개의 필드를 가지며 good이라는 단어로 시작하는 모든 레코드를 출력하고 싶을 때
NF == 4 && /^good/
빈줄을 제외한 모든 줄을 화면에 출력한다
NF > 0
awk 시스템 변수
FILENAME 현재 파일명 $0 입력 레코드
FS 입력 필드 구분 디폴트 : 공백 $n 입력 레코드의 N번째 필드
NF 현재 레코드 필드 갯수 ARGC 커맨드 라인의 인자 갯수
NR 현재 레코드 번호 ARGV 커맨드 라인 인자를 포함하는 배열
OFMT 숫자에 대한 출력 포맷 디폴트 : %.6g ENVIRON 환경 변수들을 모아둔 관계형 배열
OFS 출력 필드 구분 디폴트 : 빈줄 FNR NR과 동일 단지 현재 파일에 적용된다는 점이 다름
ORS 출력 레코드 구분 디폴트 : newline RSTART 지정한 매칭 연산을 만족하는 문자열의 맨 앞부분
RS 입력 레코드 구분 디폴트 : newline RLENGTH 지정한 매칭 연산을 만족하는 문자열의 길이
awk 연산자
산술 : =, +=, -=, *=, /=, %=
조건 : ? : 논리 : ||, &&, ! 패턴 : ~, !~
비교 : <, <=, >, >=, !=,==
증감 : ++, -- 필드참조 : $
제어문(C의 제어문과 같다)
break
continue
do {실행} while (조건)
exit
for (관계형 배열의 요소) {실행}
펄의 foreach와 같다
if (조건) {실행} else {실행}
return
while
awk 명령어
문자열 연산
gsub(reg,s)
입력 문자열의 전반에 걸쳐 정규표현식 r을 문자열 s로 대치한다
gsub(reg,s1,s2)
문자열 s2에서 정규표현식 r을 s1으로 대치한다
index(s1,s2)
s1에서 s2의 위치를 넘겨준다 만약 없다면 0을 넘겨준다
length(arg)
인자의 길이를 넘겨준다
match(s,r)
문자열 s에서 정규표현식 r과 매칭되는 부분의 위치를 넘겨준다
split(string,array[,seperator])
구분자를 기준으로(지정하지 않으면 공백 기준)해서 지정한 문자열을 배열로 만든다 배열[1], 배열[2], .......
sub(r,s), sub(r,s1,s2)
gsub과 동일하다 단지 정규표현식과 일치하는 문자열이 여러개라도 처음 문자열만 대치된다
substr(s,m)
문자열 s에서 m번째 위치에서 끝까지의 문자를 리턴한다
substr(s,m,n)
문자열 s에서 m번째 위치에서 n번째까지의 문자를 리턴한다
tolower(str)
toupper(str)
수치 연산
atan2(x,y)
y/x의 arctangent값을 라디안 단위로 넘겨준다
cos(x)
exp(arg)
int(arg)
log(arg)
rand()
0과 1사이의 난수를 발생한다
sin(x)
sqrt(arg)
srand(expr)
인자를 가지고 난수를 발생한다 인자가 주어지지 않으면 시간을 가지고 난수를 발생한다
입출력/프로세스
close(filename)
지정한 파일을 닫는다
close(cmd)
지정한 명령어 파이프를 닫는다
delete array?element
지정한 배열 요소를 지운다
getline()
다음 레코드를 읽어 들인다
getline?variable [< "filename"]
파일에서 읽어들인다
next
다음 레코드(라인)을 입력받는다 getline()과 유사하지만 /패턴/동작을 새롭게 시작한다 getline()은 다음 라인을 읽기만 한다
print ?args ?> "filename"
인자를 출력한다
printf "format" [,expressions] ?> "filename"
형식에 맞춰 출력한다
sprintf (format [,expressions])
printf와 마찬가지로 사용하는데 값을 리턴하기만 하고 출력은 하지 않는다
system(command)
시스템 내부 명령어를 실행한다
간단한 예
awk ' BEGIN { for (i = 1;i<=7,i++) print int(101*rand()) }'
화면에 1이상 100이하의 난수 일곱 개를 출력한다
ls -l file1 file2 file3 | awk ' { x += $5 } ; END { print "Total bytes : " x } '
파일들의 크기를 모두 합하여 총 바이트 수를 표시한다
awk ' END { print NR } ' filename
지정한 파일의 라인이 몇 개인지를 표시한다
awk ' NR % 2 == 0 '
지정한 파일의 짝수번째의 라인만을 출력해 준다
6 이야기 #
테이블 무너지고... 숫자 안매겨지고... 목록도 안나오네요... 아직 위키에 익숙하지 않아서, 고생하네요... 분명 특수문자의 문제라고 생각되는데.. 찾기가 힘듭니다...아시는분은 --; 수정좀 부탁드립니다. --maylinux
테이블의 경우 마지막의 "||" 뒤에 공백이 있으면 다음 줄하고 붙어버리는군요. feature 인지 bug 인지 모르겠습니다만. -- raymundo 2003-11-29 16:37:16
이걸 말씀하시는 건지 모르겠지만... 문서 상단에 ?TableOfContents를 추가하였습니다. -- 맹고이