Tips
shell 변수값 설정 방법
awk 는 child process 로 실행되므로 실행 중에 현재 shell 의 변수값을 설정할 수 없습니다. 하지만 shell eval 명령을 활용하면 shell 변수값을 설정할 수 있습니다.
for tuple in \
INTEL_FAM6_KABYLAKE_DESKTOP,0x0B,0x80 \
INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \
INTEL_FAM6_BROADWELL_CORE,0x04,0x28 \
INTEL_FAM6_HASWELL_ULT,0x01,0x21 \
INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \
INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712
do # 명령치환을 이용한 model, stepping, ucode 변수값 설정
model=$(echo $tuple | cut -d, -f1)
stepping=$(( $(echo $tuple | cut -d, -f2) ))
ucode=$(echo $tuple | cut -d, -f3)
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ]
then
. . . .
. . . .
done
-------------------------------------------------------------------------
for tuple in \
. . .
do # eval 과 awk 를 활용하여 간단히 작성
eval "$( echo "$tuple" |
awk -F, '{ printf "model=%s; stepping=%s; ucode=%s;",$1,strtonum($2),$3 }' )"
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ]
then
. . . .
. . . .
done
shell 의 declare, local, export, eval 를 이용하여도 변수값을 설정할 수 있습니다.
$ f1() {
local $( awk 'BEGIN{ print "AA=100 BB=*" }' )
echo "$AA : $BB"
}
$ f1
100 : *
shell 의 read 명령과 here document 를 이용한 방법
명령치환이 일어나야 하므로 END 구분자를 escape 하면 안됩니다.
$ IFS=, read AA BB CC <<END
$( awk 'BEGIN{ print "100,,*" }' ) # 두 번째는 empty 값
END
$ echo "$AA : $BB : $CC"
100 : : *
bash 의 경우 다음과 같은 방법도 가능합니다.
# here string 을 이용
$ IFS=, read AA BB CC <<< $( awk 'BEGIN{ print "100,,*" }' )
$ echo "$AA : $BB : $CC"
100 : : *
# source 명령과 프로세스 치환을 이용
$ source <( awk 'BEGIN{ print "AA=100 BB=*" }' )
$ echo "$AA : $BB"
100 : *
here document 를 이용한 코드 작성방법
shell 에서 제공되는 <<WORD
형식을 이용하는 here document 기능은
문서를 작성할 때 single, double quotes 을 escape 할 필요 없이 자유롭게 사용할 수 있는 장점이 있습니다.
그런데 본문 내에서 기본적으로 $
문자로 시작하는 shell 변수가 확장되기 때문에
awk 스크립트를 작성할 때는 다음과 같이 구분자로 사용되는 단어를 escape 하여
shell 변수 확장을 disable 해줘야 합니다.
# heredoc 은 stdin 에 연결되므로 '-f -' 옵션을 사용 ('-' 는 stdin 을 나타냄)
$ awk -f - <<\EOF # <<\EOF
BEGIN { ... }
EOF
$ awk -f - <<'ABC' # <<'ABC'
BEGIN { ... }
ABC
# 파이프 로인해 stdin 이 사용 중이므로 -f /dev/fd/3 를 사용
$ command ... | awk -f /dev/fd/3 3<<\EOF
BEGIN { ... }
EOF
awk 내에서 here document 작성법
awk 에서 shell 명령문을 작성할 때는 기본적으로 스트링을 이용하므로 heredoc 과같이 개행이 필요한 명령문에서는 직접 newline 문자를 사용해야 합니다.
$ awk 'BEGIN { # 오류
cmd = "cat <<END
111
222
333
END"
system(cmd)
}'
awk: cmd. line:2: cmd="cat <<END
awk: cmd. line:2: ^ unterminated string
awk: cmd. line:2: cmd="cat <<END
awk: cmd. line:2: ^ syntax error
---------------------------------------------------
$ awk 'BEGIN {
cmd = "cat <<END\n111\n222\n333\nEND" # 직접 newline 문자를 사용
system(cmd)
}'
111
222
333
만약에 shell 에서처럼 heredoc 을 작성하려면 다음과 같이하면 됩니다.
$ awk 'BEGIN {
cmd = "cat <<END\n\
${SHELL}\n\
${PWD}\n\
END"
system(cmd)
}'
/bin/bash # export 된 값으로 실질적으로는 sh 에의해 실행됩니다.
/home/mug896/tmp
$ awk 'BEGIN {
cmd = "cat <<\\END\n\
${SHELL}\n\
${PWD}\n\
END"
system(cmd)
}'
${SHELL}
${PWD}
printf 문에서 천 단위 콤마 넣기
awk 는 스크립트 내에서 필드 변수에 $
문자를 사용하기 때문에 shell 변수로 해석되는 것을
방지하기 위해 single quotes 을 이용해 작성합니다.
그런데 printf 문에서 천 단위 콤마를 넣을 때 사용하는 %'d
포멧 스트링의 경우 '
가 사용되어 문제가 되는데요.
이때는 \047
escape 문자를 사용하거나 스크립트 작성에 사용된 single quotes 을 분리한 후에
\'
나 "'"
를 이용해 연결하면 됩니다.
echo $(echo 2^64 | bc) | LC_ALL=en_US.UTF-8 awk '{ printf "%'d\n", $1 }' # Error
> ^C
$ echo $(echo 2^64 | bc) | LC_ALL=en_US.UTF-8 awk '{ printf "%\047d\n", $1 }' # OK
18,446,744,073,709,551,616
$ echo $(echo 2^64 | bc) | LC_ALL=ko_KR.UTF-8 awk '{ printf "%'\''d\n", $1 }' # OK
18,446,744,073,709,551,616
$ echo $(echo 2^64 | bc) | LC_ALL=ko_KR.UTF-8 awk '{ printf "%'"'"'d\n", $1 }' # OK
18,446,744,073,709,551,616
.....................................................................
$ awk '
BEGIN {
if ( "pidof chrome | awk \047{ print NF }\047" | getline count )
print "total chrome pids : " count
}'
total chrome pids : 45
$ awk '
BEGIN {
if ( "pidof chrome | awk '\''{ print NF }'\''" | getline count )
print "total chrome pids : " count
}'
total chrome pids : 45
include 할 수 있다
@include
키워드 와 -i
명령 옵션을 이용해 스크립트 파일을 include 해 사용할 수 있습니다.
이 기능은 awk 스크립트 파일을 라이브러리 용도로 활용하기 위한 것으로
한번 include 되어 실행되면 이후에 중복 include 가 되어도 다시 실행되지 않습니다.
파일을 찾을 때는 AWKPATH
환경 변수를 이용하는데 다음과 같이 직접 경로를 지정할 수도 있습니다.
@include "../test1"
@include "/home/abc/awklib/test2"
$ cat test1.awk
BEGIN {
print "This is script test1."
}
@include "test2"
.................................
$ cat test2.awk
BEGIN {
print "This is script test2."
}
.................................
$ awk -i test1 'BEGIN{ print "this is main" }'
This is script test1.
This is script test2.
this is main
timeout 설정 방법
awk 는 blocking read 에 대해서
millisecond 단위로 timeout 을 설정할 수 있습니다.
이것은 PROCINFO 변수에 값을 설정하는 것으로 이루어지며
개별 operation 별로 설정할 수가 있습니다.
input 값이 도착하지 않아 timeout 이 되면 blocking 이 해제되고 -1
이 반환 됩니다.
이때 ERRNO 변수값도 함께 설정됩니다.
PROCINFO[ "input_name", "READ_TIMEOUT" ] = timeout in milliseconds
# timeout 이 되면 getline 에서 -1 이 반환됩니다.
$ awk 'BEGIN {
PROCINFO["/dev/stdin", "READ_TIMEOUT"] = 5000 # 5초
printf "enter number : "
while (getline var < "/dev/stdin" > 0) {
print "entered: " var
printf "enter number : "
}
print "ERRNO: " ERRNO
}'
enter number : 111
entered: 111
enter number : 222
entered: 222
enter number : ERRNO: Connection timed out