Redirection

Awk 에서는 입, 출력과 관련된 작업을 쉘에서 redirection 을 이용할 때처럼 간단히 처리할 수 있습니다. 이때 redirection 에 사용되는 외부 파일과 명령은 단순히 스트링으로 작성하기만 하면 됩니다. 한가지 awk 사용시 인지하고 있어야될 점은 awk 는 shell 과 달리 단일 프로세스 환경이라는 점입니다. 예를 들어 파일에 쓰기 작업을 할경우 shell 의 경우는 한번 명령 실행이 완료되면 프로세스가 종료되는 것이므로 자동으로 파일과의 연결도 close 되지만 awk 의 경우는 awk 명령 실행이 종료될 때까지 유지가 되므로 필요에 따라 직접 close 함수를 이용해야 합니다.

>, >>, <, |, |&

redirection 에 의해 한번 open 된 파일, 명령은 직접 close 하지 않는이상 awk 명령이 종료될 때까지 유지되므로 이후에 내용을 추가하기 위해 따로 >> 를 사용하지 않아도 됩니다. >>> 의 차이점은 > 는 처음 파일을 open 할 때 기존 파일 내용이 삭제되는 반면에 >> 의 경우는 삭제되지 않고 기존 내용에 이어 append 됩니다.

따라서 다음 두 문장은 처음 실행될 때만 차이가 있고 이후부터는 둘 다 동일하게 append 작업이 됩니다.

# '>' 는 처음 실행될 때 기존 파일 내용이 삭제됩니다.
print "record " NR " has " NF " fields." >  "file"

print "record " NR " has " NF " fields." >>  "file"

다음의 경우는 한번 파일이 read 모드로 open 되면 이후부터는 getline 명령이 실행될 때마다 파일 포지션이 이동하여 다음번 레코드를 읽어 들이게 됩니다.

if ((getline < "file") > 0) print

다음과 같은 경우도 마찬가지로 매 사이클 마다 sort 명령이 새로 실행되는 것이 아닙니다. 처음 sort 명령이 실행될 때 한번 파이프가 open 되면 이후에는 같은 파이프로부터 연이어 다음 레코드를 읽어들이게 됩니다.

if ( "sort file" | getline ) print

다음은 한번 open 된 "sort -r" 명령에 계속해서 $1 값이 전달되고 awk 명령이 종료될 때 close 되면서 결과가 출력됩니다. 다시 말해서 sort 명령의 실행 결과가 출력되는 시점은 파이프가 close 되는 때입니다.

print $1 | "sort -r > file.sorted"

예제 )

다음은 tput 명령을 이용하여 현재 터미널의 rows 값을 조회하려고 한 것입니다. tput 명령은 결과로 한개의 라인을 출력하므로 첫번째 명령의 경우 바로 종료가 됩니다. 이렇게 되면 다음번에 터미널 창 크기를 조절했을때 변경된 값을 볼수가 없는데요. shell 에서처럼 while 문에서 매번 새로 tput 명령이 실행되게 하려면 두번째와 같이 앞서 실행된 cmd 를 close 해주어야 합니다.

$ awk '@load "time"; BEGIN { 
    cmd = "tput lines"
    while( cmd | getline v) { print v; sleep(1) }
}' 
16

$ awk '@load "time"; BEGIN { 
    cmd = "tput lines"
    while( cmd | getline v) { close(cmd); print v; sleep(1) }   # close 함수를 사용
}' 
16
16
16
13    # 터미널 창 크기를 조절한 후에 값이 바뀐다.
13
13
^C

Standard streams 의 사용

redirection 에 "/dev/stdin", "/dev/stdout", "/dev/stderr" 를 사용할 수 있습니다.

# 에러 메시지를 "/dev/stderr" 로 출력
$ awk 'BEGIN { print "ERR: test message ..." > "/dev/stderr" }' 
ERR: test message ...

# "/dev/stdin" 를 이용해 사용자로부터 입력을 받음
$ awk 'BEGIN { printf "enter your name: "
    getline name < "/dev/stdin"
    print "your name is: " name }' 
enter your name: foo bar     # 메시지 입력 후 enter
your name is: foo bar