Regular __EXPRESSION__과 Filters: sort, tr
1. sort 명령어
sort 명령어는 지정된 화일내의 각 라인을 정렬하고, 그 결과를
표준출력으로(즉; 스크린상으로) 출력한다. sort 명령어는 출력을 행함에
있어서 각각의 라인 단위로 지정에 따라서 Ascii 문자값순으로 또는
숫자값순으로 정렬한다. 만약 sort 명령어 지정시 하나 이상의 화일을
지정했을 경우에는 sort 명령어는 그 화일들을 함께 병합하여 하나의
화일로 만들어 정렬하게 된다.
sort 명령어 사용시 각 라인상에 존재하고 있는 필드들을 기준으로 해서도
정렬을 할 수 있다. 이와 같이 라인 단위의 정렬이 아닌 라인내의 필드
단위의 정렬을 수행하기 위해서는 다음과 같은 형식으로 sort 명령어를
사용한다.
sort [+pos1] [-pos2] [files]
이때 라인내의 각각의 필드들을 구별하기 위한 식별자로는 디폴트로
공백과 탭이 사용된다. 라인의 처음부터 시작하여 첫번째 필드 구별자를
만날때까지를 하나의 필드로 인식하고, 그 이후에 구별자를 만날때까지를
또하나의 필드로 인식하여 처리한다. 이때 사용되는 필드 구별자는
사용자가 sort 명령어의 -t 옵션을 사용하여 변경할 수 있다.
sort 명령어상에 필드 또는 칼럼을 지정할 경우에 주의할 것이 있다.
통상 필드 또는 칼럼에 대한 식별시에 첫번째 것을 1번 필드/칼럼이라고
계산하지만, sort 명령어에서는 첫번째 필드및 칼럼을 0번 필드/칼럼이라고
계산한다는 것이다. 이후의 필드및 칼럼도 이를 기준으로 계산된다는 것을
명심하기 바란다.
위의 명령어 형식에서 +pos1은 라인내의 대상으로하는 시작 필드를 나타내며,
-pos2는 대상 필드의 끝을 나타낸다. 예를들어 +1 -3이라고 지정하게 되면,
+1 즉 두번째 필드부터 -3 즉 네번째 필드 직전까지를 sort의 대상으로 한다.
곧 두번째 필드와 세번째 필드, 두개의 필드를 대상으로 정렬한다.
다음은 필드를 대상으로 작업하는 sort 명령어의 예제들이다.
우선 예를 들기위해 다음과 같은 화일을 가정한다.
┌─────────────────────────────────┐
│file1 │
├─────────────────────────────────┤
│-rwxrwx-wx 1 root roow 627 Jan 15 21:10 file4 │
│-rwxrw-r-x 1 wmot rodt 627 Jun 15 20:57 file7 │
│-rwxr-xrw- 1 mopt root 168 Jan 15 18:58 file8 │
│-rwxr---w- 1 root root 7 Jan 15 18:58 file6 │
└─────────────────────────────────┘
# 이 예는 일반적인 sort 명령어의 실행 결과를 보여준다.
# sort 명령어에 특정 필드에 대한 지정이 없을 경우에는 각각의 라인내에
# 들어있는 모든 문자들을 기준으로 정렬한다.
$sort file1 > file2
┌─────────────────────────────────┐
│file2 │
├─────────────────────────────────┤
│-rwxr---w- 1 root root 7 Jan 15 18:58 file6 │
│-rwxr-xrw- 1 mopt root 168 Jan 15 18:58 file8 │
│-rwxrw-r-x 1 wmot rodt 627 Jun 15 20:57 file7 │
│-rwxrwx-wx 1 root roow 627 Jan 15 21:10 file4 │
└─────────────────────────────────┘
# 이 예는 +2에서 -4 필드 지정에 의해 3번째와 4번째 필드를 대상으로
# 정렬을 수행한다.
$sort +2 -4 file1
-rwxr-xrw- 1 mopt root 168 Jan 15 18:58 file8
-rwxr---w- 1 root root 7 Jan 15 18:58 file6
-rwxrwx-wx 1 root roow 627 Jan 15 21:10 file4
-rwxrw-r-x 1 wmot rodt 627 Jun 15 20:57 file7
sort 명령어 사용시 작업의 제어를 위해서 옵션을 함께 지정할 수 있다.
옵션은 다음과 같이 두가지 형식으로 지정할 수 있다.
1) 명령어 라인상에 지정된 전체 대상(라인 또는 필드로 지정된)에
대해 옵션을 적용하는 경우
( 예 ) $sort -r file1
$sort -r +1 -2 +3 -4 file1
2) 명령어 라인상에 지정된 특정 필드만을 대상으로 옵션을 지정하고자
하는 경우(필드 지정자에 연이어 옵션을 기술한다.)
( 예 ) $sort +1n -2 file1
$sort +1n -2 +3r -4 file1
다음은 sort 명령어에서 사용 가능한 옵션들이다.
┌───┬──────────────────────────────┐
│ 옵션 │ 의 미 │
├───┼──────────────────────────────┤
│ -n │Ascii 코드순으로 정렬하지 않고, 숫자값을 기준으로 정렬한다. │
├───┼──────────────────────────────┤
│ -f │대문자와 소문자를 구별하지 않는다. │
├───┼──────────────────────────────┤
│ -b │필드들 앞에 있는 공백들을 무시한다. (반드시 대상필드를 지정)│
├───┼──────────────────────────────┤
│+pos │정렬 대상으로 할 시작 필드를 지정 │
├───┼──────────────────────────────┤
│-pos │정렬 대상으로 할 필드의 끝을 지정 │
├───┼──────────────────────────────┤
│ -tc │필드 구별자를 c 로 변경한다. │
├───┼──────────────────────────────┤
│ -r │내림차순으로 정렬한다. │
├───┼──────────────────────────────┤
│ -d │sort시에 사전(Dictionary)순으로 정렬한다. │
└───┴──────────────────────────────┘
# 다음의 예는 n 옵션을 사용하여 숫자값을 기준으로 정렬되도록 지정하고
# 있으며, 또한 r 옵션을 사용하여 내림차순으로 정렬하도록 지정하고 있다.
# 이와같이 두개의 필드를 대상으로 정렬하는 경우, 우선 첫번째 지정된
# 필드를 기준으로 정렬한후, 동일한 값이 나올경우 두번째 지정된 필드를
# 기준으로 정렬하게 된다.
$sort +4n -5 +5r -7 file1
-rwxr---w- 1 root root 7 Jan 15 18:58 file6
-rwxr-xrw- 1 mopt root 168 Jan 15 18:58 file8
-rwxrw-r-x 1 wmot rodt 627 Jun 15 20:57 file7
-rwxrwx-wx 1 root roow 627 Jan 15 21:10 file4
# 이번 예는 주목해야 한다.
# 이 예는 필드내의 임의의 칼럼들만을 대상으로 정렬 범위를 한정하는
# 방법을 보여주고 있다. 필드 지정시 +0.7 -0.8이라고 지정하면
# 첫번째 필드의 8 칼럼만을 대상으로 하여 정렬을 수행한다.
$sort +0.7 -0.8 file1 -o file1
$cat file1
-rwxrwx-wx 1 root roow 627 Jan 15 21:10file4
-rwxr---w- 1 root root 7 Jan 15 18:58 file6
-rwxrw-r-x 1 wmot rodt 627 Jun 15 20:57 file7
-rwxr-xrw- 1 mopt root 168 Jan 15 18:58 file8
( 주의 ) 파이프 라인(Pipe Line)상에 지정하는 필터를 이용하는 명령어들을
나열할 경우에는 레코드를 제거하는 명령어는 다른 명령어의
앞에 배치하는 것이 효율적이다.
예를들면 who | sort | grep stu 의 지정하지 않고,
who | grep stu | sort 형식으로지정한다.
2. tr 명령어
tr 명령어는 표준입력으로 받아들인 문자들을 지정한 문자들로 변형하여
표준출력으로 보내기 위해 사용되는 필터를 이용하는 명령어이다.
tr 명령어의 사용 형식은 다음과 같다.
tr [charset1 [charset2]]
tr 명령어의 형식에서 화일을 지정하는 부분이 없음을 주목해야 한다.
따라서 tr 명령어를 수행할때 특정 화일의 내용을 전달하기 위해서는 반드시
입력 방향전환(<) 방식을 이용해야 한다.
정규 표현식을 이용해 특정 문자들의 범위나 일련의 문자열을 1:1 로서
문자 대칭을 수행하도록 지정할 수 있다.
그리고 tr 명령어에 지정한 charset2가 charset1 보다 짧은 경우에는
charset2 내의 마지막 문자가 차이가 나는 자릿수만큼 반복되어
채워진다.
다음은 tr 명령어의 사용예를 보여주는 예이다.
┌────────────────┐
│fileA │
├────────────────┤
│Jim A. Total hours 80 │
│Steve P. Total hours 78 │
│Andy A. Total hours 80 │
│Ralph C. Total hours 40 │
│Jim A. Total hours 80 │
└────────────────┘
# 이 예는 FileA라는 화일의 내용중 8 이라는 문자를 2로 변환하도록
# 지정한 예이다.
$tr 8 2 < fileA
Jim A. Total hours 20
Steve P. Total hours 72
Andy A. Total hours 20
Ralph C. Total hours 40
Jim A. Total hours 20
# 이 예는 정규 표현식을 이용해 소문자를 대문자로 변환하는예를
# 보여주고 있다.
$tr [a-z] [A-Z] < fileA
JIM A. TOTAL HOURS 80
STEVE P. TOTAL HOURS 78
ANDY A. TOTAL HOURS 80
RALPH C. TOTAL HOURS 40
JIM A. TOTAL HOURS 80
------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: cut, paste
1. cut 명령어 : 칼럼 단위의 추출을 수행하는 필터
cut 명령어는 데이타 화일 또는 명령어의 출력으로 부터의 몇개의 필드를
추출하여, 새로운 출력을 생성하고자 할때 유용하게 쓸수 있는 명령어이다.
cut 명령어의 사용 형식은 다음과 같다.
cut -clist [ file1 file2 ... ]
다음은 cut 명령어의 옵션을 보여준다.
┌───────┰──────────────────┐
│-c 옵션 형식 ┃cut 명령어가 추출하는 내용 │
├───────╂──────────────────┤
│-ci ┃i 번째 문자를 추출 │
├───────╂──────────────────┤
│-ci,j,k ┃i, j, k 번째 문자들을 추출 │
├───────╂──────────────────┤
│-ci-j ┃i 번째 부터 j 번째 문자들을 추출 │
├───────╂──────────────────┤
│-ci- ┃i 번째 문자부터 라인의 끝까지를 추출│
└───────┸──────────────────┘
cut 명령어에서는 위와같은 -c 옵션을 통해 화일내의 각 라인에서 추출할
문자들의 위치를 지정할 수 있다. 아울러 -c 옵션의 지정 형식 몇가지를 함께
지정함으로써 보다 많은 추출 대상을 지정할 수도 있다.
예를들면 cut "-c1-5,19-"과 같이 지정하는 경우이다.
cut 명령어의 -c 옵션은 일정한 형식을 갖고있는 화일및 명령어의 출력에 대해
효과적으로 사용될 수 있다. 여기서 일정한 형식이라는 것은 예를들면은
who 명령어는 명령 실행후 표시되는 출력이 1-8 칼럼까지는 사용자명,
10-16 칼럼은 터미널, 18-29 칼럼은 로그인 날짜및 시간으로 각각의 라인이
구성되는데, 이와같이 화일내의 데이타나 명령어의 출력상의 각라인이 일정한
형식을 갖고 있는 경우를 말한다. 만일 각 라인내의 구성이 일정하지
않은 형식을 갖고 있을 경우에는 cut 명령어를 사용함에 있어 주의해야 한다.
( 주의 ) sort 명령어에서는 칼럼을 계산할 때 첫번째 칼럼을 0 칼럼이라
계산했지만, cut 명령어에서는 첫번째 칼럼을 1 칼럼으로
계산함을 주의한다.
다음은 cut 명령어의 사용형식을 보여주고 있다.
우선 예를들기 위해 일반적인 who 명령어의 출력을 보여주고 있다.
$who
root term/01 Apr 12 08:00
user1 term/00 Apr 12 09:01
user2 term/02 Apr 12 09:13
user3 term/03 Apr 12 09:15
# who 명령어의 출력을 cut 명령어의 입력으로 방향전환하여 출력중
# 1-5 칼럼까지만을 별도로 추출하여 출력하도록 지정한 예이다.
$who | cut -c1-5
root
user1
user2
user3
# 이 예는 추출 대상을 하나가 아닌 두 부분을 지정한 예이다.
$who | cut -c1-5,19-
root Apr 12 08:00
user1 Apr 12 09:01
user2 Apr 12 09:13
user3 Apr 12 09:15
지금까지는 cut 명령어를 사용하여 각 라인내의 특정한 칼럼내의 문자들을
추출하는 방법을 기준으로 설명했는데, cut 명령어에서는 각 크기가 일정하지
않는 경우 사용할 수 있는 필드를 기준으로한 추출방식도 제공하는데 그형식을
계속하여 설명한다.
2. cut 명령어 : 필드 단위의 추출
cut 명령어는 화일내에저장되어 있는 내용중 특정 필드를 대상으로 하여
추출작업을 수행하도록 해주는 명려어이다.
예를들어 사용자 등록부로 사용되는 /etc/passwd 화일을 보면, 이 화일내의
각 라인은 동일한 형식의 필드들로 구성된다. 그러나 각 필드들의 크기는
일정하지 않기 때문에 칼럼 단위의 추출은 수행하기 곤란하다. 이 경우에
필드 단위의 추출을 수행하면 용이할 것이다.
다음은 cut 명령어를 사용함에 있어 필드 단위의 처리를 수행하도록
지정하는 형식이다.
cut -flist [-dchar] [file1 file2 ...]
위의 형식에서 -flist는 추출 대상이 되는 필드 번호들을 지정하기 위한
옵션이며, -dchar는 각각의 필드들을 구별하기 위해 사용할 필드 구별자를
지정하기 위한 옵션이다.
다음은 /etc/passwd 화일을 이용하여 필드 단위의 추출 방식을 보여주는
예이다.
┌────────────────────────────┐
│/etc/passwd │
├────────────────────────────┤
│root:RHUv4kvimw:0:0:Super User:/:/bin/ksh │
│cron:NONE:1:1:Timer Daemon:/: │
│user1::100:101:555 1212:/usr/user1:/bin/sh │
└────────────────────────────┘
# 이 예에서는 필드 구별자로 :을, 추출 대상 필드를 1번과 6번 필드로
# 선언하여 cut 명령어를 수행하는 것을 보여주는 예이다.
$cut -d: -f1,6 /etc/passwd
root:/
cron:/
user1:/user/user1
3. paste 명령어
cut 명령어는 라인내의 특정 부분을 잘라내는 반면에, paste 명령어는
특정 부분을 라인내에 삽입한다는 측면에서 cut 명령어의반대의 작업을
수행한다.
paste 명령어의 형식은 다음과 같이 다양한 형식으로 지정할 수 있다.
paste file1 file2 ...
paste -d list file1 file2 ...
paste -s [-d list] file1 file2 ...
┌────────┐ ┌────────┐ ┌────────┐
│names │ │ cities │ │numbers │
├────────┤ ├────────┤ ├────────┤
│user1 │ │ Atlanta │ │(404)555-5356 │
│user2 │ │ New York │ │(212)555-3456 │
│user3 │ │ Los Angeles │ │(213)555-1234 │
└────────┘ └────────┘ └────────┘
# 이 예는 두 화일의 내용을 화일내의 기술되어 있는 순서에 따라서 라인별로
# 횡적으로 병합하는 예를 보여준다. 이때 각각의 화일로부터 발췌된 내용들
# 간에는 탭 문자 사용되어 구별된다.
$paste names numbers
user1 (404)555-5356
user2 (212)555-3456
user3 (213)555-1234
# 이 예는 세개의 화일을 횡적으로 병합한다. 병합시 각 화일로 부터 추출된
# 내용의 구별자로 탭이 아닌 = 문자와 + 문자를 사용하기 위해 -d 옵션을
# 사용하고 있다. 그런데 -d 옵션에 지정된 문자수보다 많은 화일들이
# 명령어 라인상에 지정되어 있을 경우에, paste 명령어는 지정된 문자들을
# 재사용한다.
$paste -d'=+' names cities numbers
user1=Atlanta+(404)555-5356
user2=New York+(212)555-3456
user3=Los Angeles+(213)555-1234
# 이 예는 -s 옵션을 사용하여 종방향으로 저장되어 있던 데이타를
# 횡방향으로 변환하여 출력하도록 하는 예를 보여준다.
# 이때 각각의 라인으로부터 온 내용들을 구별하기 위해 탭이 사용되어
# 지는데, 이를 제어하기 위해서 이미 설명한 -d 옵션을 함께
# 사용할 수 있다.
$paste -s names
user1 user2 user3
------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: sed
1. sed 명령어 : 쉘 프로그램에서 사용하는 편집기
sed 명령어는 데이타를 편집하기 위해 ed 편집기와 유사한 형식의
비대화식(Non-interactive) 편집기 프로그램이다.
( 비대화식 편집기는 다른 편집기와는 달리 편집기를 통해 수행할
작업 절차를 사용자가 사전에 선언해두고, 그 절차에 따라서
편집 작업을 시스템이 사용자의 제어를 받지않고 진행하는 형식으로
수행하는 편집기이다. )
이 sed 편집기는 지정한 화일을 표준출력(Standard Output)에 복사하고,
편집 명령어에 따라서 그들을 편집한다. sed 편집기의 편집 명령어들은
스크립트(script) 또는 화일에 저장해 두었다가, 실행시 -e scriptname
또는 -f filename 형식으로 sed 명령어에 전달할 수 있다.
sed 명령어의 기본 형식은 다음과 같다.
┌───────────┐
│ sed command file │
└───────────┘
위 형식에서 command의 지정 형식은 다음과 같다.
[address]cmd
여기에서 address는 ed 명령어와 동일한 형식으로 지정 가능하며,
단일 라인번호 또는 정방향의 라인 범위를 지정할 수 있다.
그리고 지정한 편집 명령어는 입력 화일내의 라인에 대해서만 작업을
수행할뿐, sed 명령어상에 선어된 새로운 라인들에 대해서는 아무런 영향을
미치지 않는다.
다음은 sed 명령어에서 사용 가능한 옵션들을 지정하는 형식을 보여준다.
sed [-n] [-e 'script] [-f file] [files]
만일 명령어에 라인번호가 지정되지 않았다면, sed 명령어는 화일내의
모든 라인에 대해 편집 명령어를 수행한다. 명령어 실행후 출력은 스크린상에
보내진다. 그러나 본래의 화일의 내용은 변경되지 않고 그대로 유지된다.
다음은 sed 명령어에 지정 가능한 편집 명령들을 정리한 것이다.
┌──┬──────────────────┬───────────┐
│명령│ 편집 내용 │ 예제 │
┝━━┿━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━┥
│ nd │ n 라인을 지운다. │5d │
├──┼──────────────────┼───────────┤
│ na\│ n 라인 직후에 연이어 지정되어 있는 │3a\ │
│ │ 라인들을추가한다. 이때 추가할라인의│this will be line 4.\ │
│ │ 끝에는 \문자를 기술해야한다. 그러나│this will be line 5.\ │
│ │ 추가할 마지막 라인에는 \를지정하지 │this will be six. │
│ │ 않는다. │ │
├──┼──────────────────┼───────────┤
│ ni\│ n 라인 직후에 연이어 지정되어 있는 │3i\ │
│ │ 라인들을삽입한다. 이때삽입할 라인의│this will be line 1.\ │
│ │ 끝에는\문자를 기술해야한다. 그러나 │this will be line 2.\ │
│ │ 삽입할 마지막라인에는 \를 지정하지 │this will be line 3. │
│ │ 않는다. │ │
├──┼──────────────────┼───────────┤
│s │ 각 라인상에 존재하는 첫번째 aa라는 │s/This/That/ │
│aa │ 문자열을 bb라는 문자열로 변환한다. │5s/This/That/ │
│bb │ 문자열을지정함에있어서 정규표현식과│/this/s/[tT]his/That │
│ │ 라인 주소를 지정할 수도 있다. │ │
├──┼──────────────────┼───────────┤
│ p │ 라인을 프린트 한다. ( 이 명령어는 │s/This/That/p │
│ │ 통상 -n 옵션이sed 명령어에 사용되었│ │
│ │ 을때 사용한다. ) │ │
├──┼──────────────────┼───────────┤
│ g │ 라인내에 존재하는 모든 문자열을 │s/This/That/g │
│ │ 대상으로 한다. │ │
└──┴──────────────────┴───────────┘
다음은 sed 명령어의 사용예를 보여주고 있다.
┌─────────────────┐
│fileA │
├─────────────────┤
│Jim A. Total hours 80 │
│Steve P. Total hours 78 │
│Andy A. Total hours 80 │
│Ralph C. Total hours 40 │
│Jim A. Total hours 80 │
└─────────────────┘
# 이 예는 정규 표현식을 사용하여 화일의 내용을 편집하여 출력하는 과정을
# 보여주는 예제들이다.
# hours라는 문자열을 time이라는 문자열로 변경한다.
$sed 's/hours/time/' fileA
Jim A. Total time 80
Steve P. Total time 78
Andy A. Total time 80
Ralph C. Total time 40
Jim A. Total time 80
# Jim이라는 문자열이 들어있는 들어있는 내용을 한번더 프린트한다.
$sed '/Jim/p' fileA
Jim A. Total hours 80
Jim A. Total hours 80
Steve P. Total hours 78
Andy A. Total hours 80
Ralph C. Total hours 40
Jim A. Total hours 80
Jim A. Total hours 80
# -n 옵션을 사용되었음으로 검색된 라인만을 표시한다.
$sed -n '/Jim/p' fileA
Jim A. Total hours 80
Jim A. Total hours 80
sed 명령어는 여러 라인의 텍스트로 구성되어 있는 스크립트(script)를
사용하여 실행할수 있다. 이때 이 스크립트는 쉘이 다른 의미로 해석하지
못하도록 보호문자를 사용하여 보호해주어야 한다. 이 경우 스크립트를
sed 명령어에 전달하기 위해서는 -e script라는 형식으로 지정해 주어야
하는데, 오직 단 하나의 명령어가 실행되는 경우에는 -e 'script' 옵션을
지정하지 않아도 된다. 또한 편집 명령어들은 특정의 화일에 저장한후,
sed 명령어에 -f 옵션을 사용하여 전달함으로써 실행할 수 있다.
┌─────────────────┐
│fileA │
├─────────────────┤
│Jim A. Total hours 80 │
│Steve P. Total hours 78 │
│Andy A. Total hours 80 │
│Ralph C. Total hours 40 │
│Jim A. Total hours 80 │
└─────────────────┘
# 스크립트를 이용하여 sed 명령어의 편집 명령들을 지정하는 예이다.
$sed '1i\
>Tom S. Total hours 60' fileA
Tom S. Total hours 60
Jim A. Total hours 80
Steve P. Total hours 78
Andy A. Total hours 80
Ralph C. Total hours 40
Jim A. Total hours 80
# 편집 명령어들을 cmdfileA라는 화일에 저장한후, 이를 이용하여
# sed 명령어를 실행하는 예를 보여준다.
┌──────────────────┐
│cmdfileA │
├──────────────────┤
│1i\ │
│Tom S. Total hours 60\ │
│Mike M. Total hours 80 │
│$d │
│s/hours/Hours/ │
│4s/Ralph/John/ │
└──────────────────┘
$sed -f cmdfileA fileA
Tom S. Total hours 60
Mike M. Total hours 80
Jim A. Total Hours 80
Steve P. Total Hours 78
Andy A. Total Hours 80
John C. Total Hours 40
------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: awk I
1. awk 명령어
1) awk 명령어의 기본 형식
awk는 유형 검색및 처리 언어 명령어로 간주되며, 대개 고차원 필터로써
사용된다. awk의 특성은 몇가지를 제외하고는 sed 명령어와 매우 유사하다.
awk 명령어의 사용방식은 sed 명령어와 동일하다.
awk ['program'] [filenames ...]
이 형식에서 주의할 것은 지정한 program은 반드시 보호문자로 묶어주어야
한다는 것이다. 이는 program 부분에 기술되어 있는 특수문자들을 쉘로부터
보호하여, awk 명령에 지정된 형식 그대로 전달하기 위해서이다.
위 형식에서 program은 다음과 같은 구조를 갖는다.
'/re/ {action}'
'/re/ {action}'
...
awk 명령어는 지정한 화일들로부터 라인단위로 입력을 읽어들여,
지정한 re 즉 정규 표현식(Regular __EXPRESSION__)으로 지정된 내용과 비교하여,
이와 일치하는 라인에 대해 각각의 정규 표현식에 상응하는 action을
수행한다.
다음은 awk 명령어를 사용하는 기본적인 형식을 보여주는 예이다.
┌───────────────────────┐
│fileA │
├───────────────────────┤
│Jim A. Total hours 80 │
│Steve P. Total hours 78 │
│Andy A. Total hours 80 │
│Ralph C. Total hours 40 │
│Jim A. Total hours 80 │
└───────────────────────┘
# 다음 예는 지정한 정규 표현식과 일치하는 모든 라인을 표시한다.
# 이와 같은 작업은 awk 명령어의 디폴트 action을 이용하면 좀더 수월하게
# 지정할 수 있는데, 그와 관련된 예제가 두번째 예제이다.
$awk '/Jim/ {print}' fileA
Jim A. Total hours 80
Jim A. Total hours 80
$awk '/Jim/' fileA
Jim A. Total hours 80
Jim A. Total hours 80
# 이 예는 awk 명령어에 정규 표현식을 지정하지 않았을때의 처리 내용을
# 보여주는 예이다. 이 경우에 지정한 action을 모든 라인에 적용한다.
$awk '{print}' fileA
Jim A. Total hours 80
Steve P. Total hours 78
Andy A. Total hours 80
Ralph C. Total hours 40
Jim A. Total hours 80
이상의 예에서는 awk 명령어에서 라인 전체를 대상으로 작업을 수행하고 있다.
2. awk 명령어에서의 필드 지정
awk 명령어는 여러개의 필드로 구성되어 있는 라인에서 특정 필드만을
대상으로 작업을 수행하도록 제한할 수도 있다.
기본적으로 awk 명령어는 라인내의 필드들을 공백이나 탭을 이용하여
라인내의 각 필드를 구별한다.
awk 명령어는 각각의 필드를 참조하기 위해 라인내의 필드 순서에 따라
$1,$2,$3,...,$NF라는 필드 지정자를 제공한다. 이 형식에서 숫자는 라인내의
필드 순서를 의미하고, NF는 라인내의 필드의 총 갯수를 나타내는 변수이다.
아울러 awk 명령어는 라인내의 전체 필드를 한꺼번에 참조할수 있는 $0 를
추가로 제공한다.
주의) awk 명령어는 필드 식별자로서, 쉘에의해 사용되는
포지셔널 파라메터와 유사한 $문자를 이용한다.
fileA
┌───┬──┬────┬────┬──┐
│$1 │ $2 │ $3 │ $4 │ $5 │
├───┼──┼────┼────┼──┤
│Jim │ A. │ Total │ hours │ 80 │
│Steve │ P. │ Total │ hours │ 78 │
│Andy │ A. │ Total │ hours │ 80 │
│Ralph │ C. │ Total │ hours │ 40 │
│Jim │ A. │ Total │ hours │ 80 │
└───┴──┴────┴────┴──┘
# 이 예는 지정한 정규 표현식과 일치하는 문자열을 갖고있는 라인중
# 사용자가 지정한 필드만을 표시하도록 하는 예이다.
# 결과를 보면 80 이라는 숫자가 두번 표시되는데 이는 action에서 지정한
# $5 가 라인의 가장 마지막 필드이기 때문에, $NF에 의해 한번더
# 표시되기 때문이다.
$awk '/Jim/ {print $1 $5 $NF}' fileA
Jim8080
Jim8080
# 위의 결과를 보면 추출한 각 필드가 마치 하나의 필드처럼 출력되는 것을
# 볼수 있다. 이 경우 각각의 필드를 구별하기 위해서 다음과 같이 공백이
# 표시되도록 지정할 수 있다.
$awk '/Jim/ {print $1 " " $5 " " NF}' fileA
Jim 80 5
Jim 80 5
# 이 예는 정규 표현식으로 지정한 문자열과 일치하는 라인들의 전체 내용을
# $0를 사용하여 모두 표시되도록 지정한 예이다.
$awk '/Jim/ {print $0}' fileA
Jim A. Total hours 80
Jim A. Total hours 80
이상의 예에서는 필드 지정자를 사용하여 라인내의 특정 필드들을 발췌하여
출력을 작성하고 있다.
3. 정형화된 출력 생성
awk 명령어는 보다 정형화된 출력을 작성할 수 있도록 하기 위해서
C 언어의 printf() 함수와 유사한 printf 문장을 제공한다.
printf 문장을 사용하는 형식은 다음과 같다.
┌──────────────────┐
│ printf("제어 문자열",인자_list) │
└──────────────────┘
이 형식에서 제어 문자열에는 화면상에 표시할 문자열과 지정한 인자들을
표시하는 형식을 지정하는 형식 변환문자를 지정한다. 그리고 인자_list에는
이전에 설명했던 필드 지정자 또는 임의의 값등을 지정할 수 있다.
제어 문자열에 지정되어 있는 각각의 형식 변환문자들은 인자_list상에 지정된
인자들과 순서에 따라서 대치된다. 이때 지정된 형식 변환문자에 따라
인자로 지정된 값이 변환되어 대치된다. 또한 제어 문자열에는 new line을
의미하는 \n 문자와 탭 문자를 의미하는 \t를 함께 지정할 수 있다.
다음은 제어 문자열에서 지정 가능한 형식 변환문자들을 보여준다.
┌────────┰─────────────────┐
│ 형식 변환문자 ┃ 의 미 │
┝━━━━━━━━╋━━━━━━━━━━━━━━━━━┥
│ %d ┃ decimal integer │
├────────╂─────────────────┤
│ %o ┃ octal number │
├────────╂─────────────────┤
│ %x ┃ hexadecimal number │
├────────╂─────────────────┤
│ %u ┃ unsigned decimal number │
├────────╂─────────────────┤
│ %e ┃ scientific notation │
├────────╂─────────────────┤
│ %f ┃ floating point decimal number │
├────────╂─────────────────┤
│ %g ┃ the smaller of %e or %f │
├────────╂─────────────────┤
│ %c ┃ single character │
├────────╂─────────────────┤
│ %s ┃ character string │
└────────┸─────────────────┘
다음은 printf 문자를 사용하는 예를 보여준다.
$who
root term/01 Apr 12 08:00
user1 term/02 Apr 12 09:01
# 이 예에서 %s라는 형식 변환 문자가 두개가 지정되어 있다.
# 이들은 후속되는 인자들과 대치되게 되는데 첫번째 %s는 $1과
# %s는 $5와 대치되어 출력된다. 이때 지정한 형식 변환문자에
# 따라서 인자의 값을 변환하여 대치하는데 이 예에서는
# 문자열 그대로 처리된다. 또한 매 라인이 출력될때마다
# 새로운 라인에 출력되도록 하기 위해서 \n이 사용되고 있다.
$who | awk '{printf("%s logged on at %s\n", $1, $5)}'
root logged on at 08:00
user1 logged on at 09:01
------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: awk II
4) awk 명령어의 옵션
awk 명령어는 -f 와 -F 라는 두개의 옵션을 제공한다. 이들 옵션을 사용하는
형식은 다음과 같다.
awk [-Fc][-f file] [filenames...]
-f 옵션은 awk 명령어에 지정할 'program' 부분을(이전 강의의 awk 명령어의
문법을 참조) 임의의 화일에 저장해 둔후, awk 명령어에 그 화일을 알려주기
위해 사용하는 옵션이다.
awk 명령어는 지정 화일속의 라인내의 필드 구별자로 디폴트로 공백을
사용하는데, 이들 문자 이외의 문자를 필드 구별자로 처리하고자
할 경우에는 -F 옵션을 사용하여 임의의 구별자를 선언할 수 있다.
예를들면 /etc/passwd 화일내의 각각의 라인은 :이 필드 구별자로
사용되고 있는데, 이 경우 -F:이라고 지정하면 awk는 이 화일을 처리할 때
필드 구별자로 :을 사용하게 된다.
다음은 awk 명령어의 옵션을 사용하는 예를 보여주고 있다.
┌─────────────────────────┐
│myfile │
├─────────────────────────┤
│/user/ {print $1 " " $7} │
└─────────────────────────┘
┌─────────────────────────┐
│/etc/passwd │
├─────────────────────────┤
│root:x:0:1:root admin:/: │
│sa:x:0:0:sa menus login:/sa:/sa/sa.exec │
│user1:x:200:200:UNIX user:/usr/user1:/bin/rsh │
│user2:x:201:200:UNIX user:/usr/user2:/bin/rsh │
│user3:x:202:200:UNIX user:/usr/user3:/bin/rsh │
└─────────────────────────┘
# 이 예는 필드 구별자로 :을 사용하고 있는 /etc/passwd 화일을 처리
# 하기위해 -F 옵션을 사용하고, awk 명령어에 지정할 'program'을
# myfile이라는 화일에 저장해둔후 이를 awk 명령어에 전달하기 위해
# -f 옵션을 사용한 예를 보여주고 있다.
$awk -F: -f myfile /etc/passwd
user1 /bin/rsh
user2 /bin/rsh
user3 /bin/rsh
5) awk 명령어의 연산자
awk 명령어의 'program' 부분은 '/re/ {action}'의 두 부분으로 구성된다.
이 형식에서 re(Regular__EXPRESSION__)와 action 부분을 구별하기 위해서
action 부분을 중괄호로 둘러쌓도록 되어 있다. 이때 action 부분에는
지정한 Regular __EXPRESSION__에 의해 선택된 라인에 대해서 수행할 작업 내용을
지정한다. action은 awk 명령어가 제공하는 다양한 연산자를 사용하여
세부적인 제어가 가능하다.
awk 명령어에서 사용 가능한 연산자들은 다음과 같다.
┌─────────────────┰─────────────┐
│ Math Operator ┃ 의 미 │
├─────────────────╂─────────────┤
│= += -= *= /= %= ┃할당 연산자 │
├─────────────────╂─────────────┤
│> >= < <= == != ~ |~ ┃관계 연산자 │
├─────────────────╂─────────────┤
│ ┃문자열 연결 │
├─────────────────╂─────────────┤
│+ - ┃덧셈, 뺄셈 │
├─────────────────╂─────────────┤
│* / % ┃곱셈, 나눗셈, 나머지 │
├─────────────────╂─────────────┤
│++ -- ┃증감 연산자 │
└─────────────────┸─────────────┘
┌─────────────────┰─────────────┐
│ Boolean Operator ┃ 의 미 │
├─────────────────╂─────────────┤
│|| ┃ 논리적 OR │
├─────────────────╂─────────────┤
│&& ┃ 논리적 AND │
├─────────────────╂─────────────┤
│| ┃ 논리적 NOT │
└─────────────────┸─────────────┘
┌─────────────────┰─────────────┐
│정규 연산식 연산자 ┃ 의 미 │
├─────────────────╂─────────────┤
│~ == ┃ 문자열 일치 │
├─────────────────╂─────────────┤
│!~ ┃ 문자열 불일치 │
├─────────────────╂─────────────┤
│ ┃ 문자열 연결 │
├─────────────────╂─────────────┤
│= ┃ 문자열 할당 │
└─────────────────┸─────────────┘
위의 연산자들중 몇가지 연산자를 소개한다.
다음과 같은 할당 연산자들이 수행하는 연산은 다음과같다.
a += 5 ------> a = a + 5
a -= 5 ------> a = a - 5
a *= 5 ------> a = a * 5
a /= 5 ------> a = a / 5
a %= 5 ------> a = a % 5
Boolean 연산자중 논리적 OR를 나타내는 || 연산자가 두개의 연산식 사이에
지정되었을때, 두개의 연산식중 하나만이라도 참이면 그 연산 결과는
참으로 된다. 이때 앞에 기술된 연산식이 참일 경우에는 뒤에 기술되어 있는
연산식은 평가되지 않는다는 것을 주의해야 한다. 이는 프로그램 작성시
오류를 범할 가능성이 있으니 꼭 기억하기 바란다.
그리고 논리적 AND를 나타내는 && 연산자가 두개의 연산식 사이에
지정되었을때, 두개의 연산식 모두가 참이어야만 참으로 된다.
이때 앞에 기술된 연산식이 거짓일 경우에는 뒤에 기술되어 있는
연산식은 평가되지 않는다는 것도 유의해야 한다.
~와 !~ 연산자들은 Regular __EXPRESSION__과 함께 사용된다.
이때 ~ 연산자는 일치(match), !~는 불일치(no-match)를 나타낸다.
둘 또는 그이상의 연산식들이 연산자를 통해 연결되지 않았을 경우에는
이들 연산식은 하나의 문자열로 연결된다. 예를들면 다음과 같다.
"code " 5+5 라고 지정되어 있으면
"code 10"의 하나의 문자열로 결합된다.
( 주의 ) 연산식내에 특수 문자를 사용할 경우에 쉘의 처리를 막기 위해
반드시 보호문자로 둘러 쌓아야 한다.
다음은 awk 명령어의 연산자 사용 예를 보여준다.
# 다음 예는 각각의 awk 예제에서 입력으로 사용할 ls -l의 출력을
# 보여주고 있다.
$ls -l
Total 4
-rwxrwxrwx 1 cuser cusers 624 Jan 15 21:10 file1
-rwxrwxrwx 1 cuser cusers 627 Feb 15 20:57 file2
-rwxrwxrwx 1 cuser cusers 168 Jan 15 18:58 file3
-rwxr--r-- 1 root cusers 576 Jan 15 18:58 myfile
# 다음 예는 첫번째 표현식에 지정된 $9 즉 9번째 필드의 내용중
# 정규 표현식으로 지정된 file이라는 문자열과 일치하는 (~ 연산자를
# 사용하였음으로) 문자열이 있는 라인을 검색하여, 그 라인의 9번째 필드의
# 내용만을 출력하도록 지정한 예이다.
$ls -l | awk '$9 ~ /file/ {print $9}'
file1
file2
file3
myfile
# 위의 예에서는 해당 필드에서의 위치와 상관없이 file이라는 문자열이
# 있으면 처리의 대상으로 사용하고 있다. 만일 지정한 문자열이 필드의
# 첫 칼럼부터 지정되어 있는 문자열만을 처리의 대상으로 사용하고자
# 한다면, 문자열을 지정하는 정규 표현식내에 ^문자를 함께 기술하면 된다.
# 다음은 그에 해당하는 예이다.
$ls -l | awk '$9 ~ /^file/ {print $9}'
file1
file2
file3
# 다음 예에서는두개의 연산식을 함께 지정할때 지정 형식을 보여주는
# 예제이다.
# 이 예는 입력에 대해 각각의 라인별로 검색하여, - 문자가 첫 칼럼에
# 기술되어 있는 라인의 3번 필드와 6번 필드를 공백을 사이에 위치시켜
# 조합한후, 그를 string이라는 변수에 저장한 후 그 내용이
# "cuser Jan"이라는 문자열과 비교하여, 같을경우 그 라인의 9번째
# 필드를 출력하도록 프로그램 되어 있다.
# 이 프로그램에서 주목할 것은 = 은 대입 연산자이고, == 연산자가
# 등호 연산자라는 것이다. 그리고 '$3 " " $6'의 지정은 문자열 연결이
# 수행되어, 하나의 문자열로 결합된다.
$ls -l | awk '/^-/ {string = $3 " " $6}
>string == "cuser Jan" {print $9}'
file1
file3
# 위의 프로그램과 같은 결과는 다음과 같은 프로그램을 사용해서도
# 동일한 결과를 얻을 수 있다.
┌──────────────────────────────┐
│ ls -l | awk '/^-/ && "cuser" && $6 == "Jan" {print $9} │
└──────────────────────────────┘
# 다음예는 쉘 프로그램내에서 awk 명령어가 사용되는 것을 보여주고 있다.
┌────────────────────────────────┐
│prog │
├────────────────────────────────┤
│echo FILE "\t" SIZE "\t" RUNNING-TOTAL │
│ls -l | awk '/^-/ {total = total + $5 } │
│ {print $9 "\t" $5 "\t" total}' │
└────────────────────────────────┘
# 위의 프로그램을 분석해 보자. 우선 echo 명령어를 통해 출력상에 표시할
# 표제를(Header) 지정하고 있다. 그 후 ls -l 명령어의 실행 결과를
# awk 명령어의 표준 입력으로 처리하고 있다. 그 결과에 대해 라인내의
# 첫 칼럼이 -인 라인의 5번째 칼럼의 내용을 total 이라는 변수에
# 누적한후, 9 번째 필드, 5 번째 필드 그리고 누적값을 출력하도록
# 하는 프로그램이다. 이때 출력상에 포함되는 각각의 데이타는 정형화된
# 출력을 위해 \t 즉, 탭을 찍어주고 있다.
$prog
FILE SIZE RUNNING-TOTAL
file1 624 624
file2 627 1251
file3 168 1419
myfile 576 1995
--------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: awk III
5) awk의 응용
(1) awk의 함수(Built-in Functions)
getline()
다음 입력 레코드가 현재의 레코드를 대치한다.
getline 함수는 다음의 입력 레코드가 있을 경우에는 1을 돌려준다.
만일 다음의 입력 레코드가 없을 경우에는 0이 돌려진다.
이 함수가 실행된후 처리된 라인수를 돌려주는 NR(Number of Record)
변수가 갱신된다.
index(s1, s2)
s1에 지정된 string내에서 s2로 지정한 substring을 검색한다.
발견시에는 substring이 지정되어 있는 string내의 위치를
되돌려준다. 만일 발견되지 않으면 0을 돌려준다.
length()
length(string)
length 함수는 현재의 입력 레코드를 내의 문자수를 확인하기 위해
인자없이 사용하거나, string내의 문자수를 확인하기 위해 인자로써
string을 지정하여 사용한다.
split(string, array, sep)
지정한 string을 필드로 구분하여 지정한 array 배열내에 저장한다.
이때 string내에서 필드를 구별하기 위한 필드 구별문자로는
`지정한 sep가 사용된다. 그리고 각각의 필드가 저장될 배열요소는
array[1],array[2],array[3],..등이 된다. split 함수는 실행후
필드의 갯수를 돌려준다.
sprintf(fmt, string, ...)
지정한 fmt(Formatting String)에 따라서 문자열을 형식 변환한다.
substr(string, pos, n)
지정한 string에서 pos로 지정한 문자부터 n개의 문자를 발췌한다.
함수 사용시 pos로 지정한 값이 1보다 적으면 1이 가정되고,
n이 1보다 적으면 Null이 되돌려진다.
이상의 함수 이외에도 다음과 같은 수학 연산용 함수를 추가로 제공한다.
cos(expr) expr의 cosine 값을 돌려준다.
sin(expr) expr의 sine 값을 돌려준다.
log(expr) expr의 log 값을 돌려준다.
int(expr) expr의 값중 정수부만을 돌려준다.
exp(expr) expr의 지수값을 돌려준다.
다음은 awk에서 지원하는 함수를 사용하는 예를 보여준다.
$ls -l |
>awk '/^-/ {printf("Filename %s is %d characters long\n",$9,
>length($9))}'
Filename datafile is 8 characters long
Filename file1 is 5 characters long
Filename myfile is 6 characters long
Filename prog is 4 characters long
# 위의 프로그램에서는 ls -l 명령어의 출력을 awk 명령어의 표준 입력으로
# 처리하고 있다. 이때 ls -l 명령어의 출력 라인내의 9번째를 필드를
# 형식화(Formatting)하여 출력하고 있다. 이 예에서는 length() 함수를
# 사용하고 있다. length() 함수는 지정한 문자열의 문자수를 돌려주는데,
# 실행 결과의 화일명의 문자수가 표시되는 것을 보고 이를 확인할 수 있다.
(2) awk의 특수 유형(Special Pattern)
awk 명령어는 BEGIN과 END라는 두개의 특수 유형을 갖고 있다.
BEGIN에 지정한 action은 첫번째 입력 라인을 읽어들이기 전에 수행된다.
그래서 통상 BEGIN은 프린트 헤더를 생성하기 위해, 변수를 초기화하기 위해
또는 필드 구별자를 설정하기 위해 사용된다.
END로 지정한 action은 마지막 입력 라인이 처리된후에 실행된다.
다음은 BEGIN과 END가 지정되어 있을때 awk 명령어의 실행 흐름을 보여주는
그림이다.
$awk 'BEGIN {FS = ":"} $2 == "" END {print NR}' /etc/group
# 이 예는 패스워드를 갖지않는 /etc/group 화일내의 모든 사용자를
# 프린트한다. 모든 레코드들이 처리되면, 처리된 레코드의 전체 갯수가
# 프린트된다.
# 이 예에서는 처리된 레코드의 전체 갯수를 돌려주는 변수인 NR 변수를
# 사용하고 있다.
│
┌─────┴──────┐
│필드 구별자를 :으로 설정│
└─────┬──────┘
┌────────┐
│레코드를 읽는다.│
┌─┴────────┴─┐
No │ 레코드의 검색이 │ Yes
┌──┤ 성공적으로 수행됐는가? ├───┐
│ └─┬────────┬─┘ ┌─┴─────┐No
│ │다음 레코드 처리│ │현재 레코드의 ├─┐
│ └──┬─────┘ │$2가 ""인가 │ │
│ │ Yes └─┬─────┘ │
┌──┴──┐ │ ┌────┴────┐ │
│NR을 출력 │ │ │현재 레코드를 출력│ │
└──┬──┘ │ └────┬────┘ │
│ └───────────┴───────┘
다음은 awk의 특수 유형을 사용하는 예이다.
이 예는 화일 시스템당 자유 블럭의 평균 갯수와 함께 시스템내의 모든
화일 시스템들의 자유 블럭의 전체 갯수를 돌려주는 프로그램이다.
이 예에서 사용될 df 명령어의 출력 구성은 다음과 같다.
┌──< 필드 구별자를 공백으로 보았을때의 필드 식별자
┌───┴───────────────────────────┐
│$1 $2 $3 $4 $5 $6 │
└───────────────────────────────┘
/ (/dev/dsk/c0d0s1 ): 72520 14825 i-nodes
/ADMIN (/dev/dsk/c0d0s3 ): 70960 1196 i-nodes
( 각각의 필드에 대한 자세한 설명은 차후 강의될 유닉스
관리자 과정에서 자세히 설명됩니다. )
$df | awk '{s = s + $4} END {print s, s/NR}'
143480 71740
# 이 예에서 출력상의 각각의 라인에 대해, awk 명령어는 s=s+$4를 수행한다.
s=72520
s=72520+70960
# 이 프로그램에서 레코드 처리의 끝에서, awk 명령어는 s 변수의 값과
# NR 변수의 값을 프린트한다.
s=143480
NR=2
--------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: awk IV
6) awk의 제어문
(1) if 제어문
awk 명령어 내에서도 조건판단에 따른 작업 제어를 수행할 수 있는
if 제어문을 수행할 수 있다. awk 명령어에서 지정 가능한 if 제어문의
기본 형식은 다음과 같다.
if (condition-__EXPRESSION__)
action
[else]
action
다음은 awk 명령어에서 if 제어문을 사용한 예이다.
┌────────────────────────────────┐
│ avsize │
├────────────────────────────────┤
│ /bin/df | /usr/bin/awk '{ s = s + $4} │
│ END { │
│ if (s/NR <= 40000) │
│ printf(Average File System Size is: %d\n", s/NR) │
│ else │
│ printf("*** WARNING AVERAGE FILE SYSTEM SIZE IS: %d. \ │
│ ACTION REQUIRED\n",s/NR) │
│ }' │
└────────────────────────────────┘
$sh avsize
Average File System Size is: 122083
위의 예는 df 명령의 실행 결과를 awk 명령어에 표준입력 처리하고 있다.
그후 awk 명령어는 출력상의 각각의 라인내의 4번째 필드 즉, 화일 시스템의
총합계를 구한후 이를 s 변수에 저장한후, END 연산식내에서 if문을 수행한다.
if 제어문에서 s 변수에 저장된 값(즉, 모든 화일시스템의 합계)을
df 명령어의 출력 라인수(즉, 화일 시스템의 갯수)로 나누어 화일 시스템의
평균치를 구한후 이 값이 40000보다 적거나 같은지를 판단하여, 조건이
참이면 그 평균치를 알려주는 메세지를 표시하고, 거짓일 경우에는
WARNING 메세지를 표시하도록 작성한 프로그램이다.
( 주의 ) awk if 명령어와 Shell의 if 명령문과 혼돈하지 말아야 한다.
(2) loop 제어문
awk 명령어에서는 if 제어문과 더불어 다음과 같은 두가지 loop 제어문을
지원한다.
for(initializeCounter; testCounter; incrementCounter)
action
while(condition-__EXPRESSION__)
action
위의 두가지 loop 제어문상에 하나 이상의 action을 지정하기 위해서는
중괄호({})로 묶어주어야 한다.
( 주의 ) awk 명령어의 for와 while 제어문과 Shell의 for와 while 제어문을
혼돈하지 말기 바란다.
다음은 loop 제어문의 처리 과정을 보여주는 그림이다.
while loop for loop
│ │
├────────┐ ┌──┴──┐
┌──┴──┐참 ┌──┴──┐ initialize counter
│ test ├──┤ action(s)│ ┌─┴─────┴─┐
└──┬──┘ └─────┘ ┌─┤test counter ├───┐
│거짓 거짓│ └─┬─────┬─┘참 │
│ │ increment counter │
│ └──┬──┘ ┌──┴──┐
│ │ │ action(s)│
│ │ └──┬──┘
│ └────────┘
│
다음은 loop 제어문을 사용하는 예제이다.
┌───────────────────────────────┐
│ file2 │
├───────────────────────────────┤
│ Mary Jones 20000 │
│ Harriet Forbes 40000 │
│ Tom Jenkins 45000 │
└───────────────────────────────┘
$awk '$1 == "Harriet"\
> {for (salary=$3; salary < 60000; salary = salary * 1.1)
> printf("Salary is %d. Keep working\n",salary)}' file2
Salary is 40000. Keep working
Salary is 44000. Keep working
Salary is 48400. Keep working
Salary is 53240. Keep working
Salary is 58564. Keep working
이 예에서는 awk 명령어는 입력 라인의 첫번째 필드에서 Harriet이라는
문자열이 존재하는지를 검색한다. 만일 해당 문자열이 있을 경우에는
for 제어문을 수행한다. 다음은 for 제어문에의해 수행되는 과정을
요약한 것이다.
1. salary 변수에 세번째 필드에 있는 값을 설정한다.(즉, 40000)
2. salary 변수의 값이 60000보다 적은지를 검사한다.
3. 검사 결과가 참이면 printf 명령문을 수행한다.
4. 그후 salary 변수에 1.1을 곱한다.
5. 그후 다시 salary 변수의 값이 60000 보다 적은지를 다시 검사한다.
검사 결과가 참이면 또한번 printf 명령문을 수행한후 3번에서
5번까지의 단계를 거짓이 될때까지 계속적으로 반복 수행한다.
6. 이 예에서는 salary 변수의 값이 64420이 될때 검사가 거짓이되어
loop를 종료한다.
┌───────────────────────────────┐
│ file1 │
├───────────────────────────────┤
│ somefield otherfield 9999 whoknows │
│ information junk 45 │
└───────────────────────────────┘
$awk '{n=1
> while(n <= NF)
> {printf("%s:",$n)
> n = n + 1}
> printf("\n)}' file1
somefield:otherfield:9999:whoknows:
information:junk:45:
이 예에서는 awk 명령어가 입력 화일의 모든 라인에 대해서 지정한 작업을
수행하게 된다. 각각의 라인에 대해 수행되는 작업은 다음과 같다.
1. n 이라는 변수가 1로 설정된다.
2. n 변수의 값이 화일내의 필드 수보다 적거나 같은 동안은 참이되고,
라인내의 각각의 필드의 내용이 : 구별자를 사용하여 모두 프린트
되어진다. 그리고 n 변수의 값이 n+1이 된다.
3. n 변수의 값이 화일내의 필드 수보다 클경우에는 거짓이 되어,
\n(New line) 문자가 프린트된다.
7) awk 명령어를 마치면서
다음은 awk 명령어를 소개를 마감하면서, 이전에 awk 연산자를 소개하면서
사용했던 예제를 awk 제어문을 사용하여 작성하여 다시한번 소개한다.
┌───────────────────────────────┐
│ prog │
├───────────────────────────────┤
│ ls -l | awk ' │
│ BEGIN {print "\nFILE\tSIZE\tRUNNING-TOTAL\n"} │
│ /^-/{total=total+$5 │
│ print $9 "\t" $5 "\t] total} │
│ END {print "\nTotal is "total is " total "\n"}' │
└───────────────────────────────┘
$prog
FILE SIZE RUNNING-TOTAL
file1 624 624
file2 627 1251
file3 168 1419
myfile 576 1995
Total is 1995
--------------------------------------------------------------------------
Filter와 Regular __EXPRESSION__: 실전문제
1. 현재 시스템에 로그인하고 있는 모든 사용자를 표시하는 who 명령어의 출력을
터미널 식별명을 기준으로 정렬하여 출력하도록 하는 명령어 라인을 작성하시오.
( sort, who 명령어를 참고한다. )
출력예)
bin con Jun 20 19:00
root console Jun 20 08:10
user09 term/06 Jun 20 10:01
user10 term/04 Jun 20 10:02
힌트) 필드 구별자로 슬레쉬를 사용하거나 문자 위치를 기준으로 정렬한다.
2. 시스템상에서 ps -el 명령의 실행 결과로 출력되는 내용중, 현재 실행되고 있는
sh 프로세스들만을 표시하도록하는 명령어 라인을 작성하시오.
( ps 와 grep 또는 ps 와 awk 명령어를 이용. )
출력예)
28722 console 0:02 sh
25855 con 0:01 sh
185 con1 0:00 sh
3. who 명령어의 출력에서 사용자 이름과 터미널명만을 발췌하여 출력하는
명령어 라인을 작성하시오. 이때 출력은 터미널 식별명을 기준으로 정렬하여
표시한다.
출력예)
bin con
root console
user10 term/04
user09 term/06
힌트) / 를 필드 구별자로 이용한다.
4. 시스템내에서 ps -el 명령어의 실행 결과로 생성되는
수행중인 모든 프로세스에 대한 정보를 표시하는 쉘 프로그램을 작성하시오.
이때 출력 결과를 PPID 필드를 첫번째 sort key로, PID를 두번째 sort key로
해서 정렬하도록 출력 내용을 조정하여 출력한다. 이때 각각의 컬럼 헤더는
변경되지 않도록 주의한다.
출력예)
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD
19 S 0 0 0 0 60 20 8009f465 2 c008f0d0 ? 0:01 sched
10 S 0 1 0 0 60 20 80198465 18 e0000000 ? 19:41 init
19 S 0 2 0 0 60 20 8019c465 0 c0015b60 ? 0:00 vhand
18 S 0 201 1 0 64 24 8027a465 14 d0130b70 ? 0:00 fssel
19 S 309 28722 1 0 60 20 801cf465 23 c008ebf8 console 0:01 sh
5. 사용자 등록부인 /etc/passwd 화일에 새로운 사용자에 대한 정보를 등록하는
쉘 프로그램을 작성하시오. 새로운 사용자에 대한 정보는 /etc/passwd 화일의
가장 마지막 라인에 추가하도록 한다. 참고로 /etc/passwd 화일에 저장되는
개개의 사용자에 대한 정보는 다음과 같은 형식의 한 라인으로 구성된다.
┌────────────────────────────┐
│ (Login-id):x:(UID):(GID):(Comment):(Home):(Shell) │
└────────────────────────────┘
() 부분은 사용자로부터 입력을 받아들여 처리하도록
프로그램을 작성한다.
라인내의 각각의 필드의 의미는 다음과 같다.
Login-id : 사용자의 로그인 이름
UID : 사용자를 식별하는 번호
GID : 사용자의 소속 그룹을 식별하는 번호
Comment : 사용자에 관련된 주석
Home : 사용자의 홈 디렉토리
Shell : 로그인을 수행했을때 최초에 개시되는 프로세스
위의 라인을 화일에 저장하기 위해서는 sed 명령어를 이용한다.
힌트) 프로그램을 작성하다보면 sed 명령어상에서 사용되는 \(역슬레쉬)의
특수 의미를 제거해야 할 필요를 느끼게 될 것이다.
힌트) sed 명령어의 출력을 /etc/passwd 화일에 저장하도록 프로그램을
작성한다.
'Academy I > Tech Academy' 카테고리의 다른 글
SQL로 하둡 쿼리를 처리하는 방법 10가지 (0) | 2014.12.11 |
---|---|
Unix 14 Shell Programming의 추가사항 (0) | 2014.12.04 |
Unix 13 쉘 프로그램의 제어문 (0) | 2014.12.04 |
Unix 12 Shell Program Debugging I (0) | 2014.12.04 |
Unix 10 Shell Program에서 쉘 특수 변수의 이용 (0) | 2014.12.04 |
Unix 9 본쉘, 콘쉘 (0) | 2014.12.04 |
Unix 8 쉘프로그래밍 (0) | 2014.12.04 |
Unix 7 프로세스, 쉘 (0) | 2014.12.04 |