String functions

sub ( regex, replacement [, target ] )

gsub ( regex, replacement [, target ] )

sub 와 gsub 함수를 함께 설명합니다. regex 에는 상수 (/.../) 와 quotes ("...") 모두 사용할 수 있습니다. sub 함수는 첫 번째 매칭에 대해서만 치환을 하고 gsub 함수는 전체 매칭에 대해서 모두 치환을 합니다. 반환값은 치환이 일어난 개수인데 sub 함수의 경우는 한번만 치환을 하므로 1 또는 0 이 됩니다. target 스트링이 주어지지 않으면 기본적으로 $0 이 사용됩니다.

########################  sub  #########################
$ awk '
BEGIN {
    str = "foo boo zoo"
    num = sub(/o+/, "XX", str)
    print str
    print "number of substitutions made : " num
}'
fXX boo zoo
number of substitutions made : 1
...............................................

# target 스트링이 주어지지 않으면 `$0` 가 사용됩니다.
$ echo foo boo zoo | awk ' {
    num = sub(/o+/, "XX")
    print
    print "number of substitutions made : " num
}'
fXX boo zoo
number of substitutions made : 1

########################  gsub  #########################
$ awk '
BEGIN {
    str = "foo boo zoo"
    num = gsub(/o+/, "XX", str)
    print str
    print "number of substitutions made : " num
}'
fXX bXX rXX
number of substitutions made : 3
................................................

# target 스트링이 주어지지 않으면 `$0` 가 사용됩니다.
$ echo foo boo zoo | awk ' {
    num = gsub(/o+/, "XX")
    print
    print "number of substitutions made : " num
}'
fXX bXX rXX
number of substitutions made : 3

& 는 매칭된 스트링을 나타내고 replacement 부분에서 사용될 수 있습니다.

########################  sub  #########################
$ awk '
BEGIN {
    str = "foo BAR ZOO"
    num = sub(/[A-Z]+/, "@&@", str)
    print str
}'
foo @BAR@ ZOO

########################  gsub  #########################
$ awk '
BEGIN {
    str = "foo BAR ZOO"
    num = gsub(/[A-Z]+/, "@&@", str)
    print str
}'
foo @BAR@ @ZOO@

regex 문자인 |& 를 일반 문자로 사용하려면 escape 해야 합니다. regex 상수(/.../) 와 달리 quotes 에서는 기본적으로 escape sequence 가 처리되므로 \& 가 전달되기 위해서는 \ 문자를 두번 사용해야 합니다.

########################  sub  #########################
$ awk '
BEGIN {
    str = "foo|boo|zoo"
    num = sub(/\|/, "\\&", str)
    print str
}'
foo&boo|zoo

########################  gsub  #########################
$ awk '
BEGIN {
    str = "foo|boo|zoo"
    num = gsub(/\|/, "\\&", str)
    print str
}'
foo&boo&zoo

gensub ( regex, replacement, how [, target ] )

gensub 는 sub, gsub 함수와 달리 치환된 스트링 결과가 target 스트링에 설정되지 않고 함수의 return 값으로 전달됩니다. target 스트링이 주어지지 않았을 경우 입력값으로는 $0 이 사용되나 출력값은 $0 에 대입되지 않으므로 직접 $0 나 변수에 대입해서 사용해야 됩니다. gensub 는 다음과 같이 gsub 함수에 비해 좀 더 확장된 기능을 가지고 있습니다.

how 인수를 통해서 매칭 번호를 지정할 수 있습니다. ( 1, 2, 3 ... 9, "g" )

$ awk '
BEGIN {
    str = "foo BAR ZOO"
    res = gensub(/[A-Z]+/, "@&@", 1, str)      # how : 1
    print res
}'
foo @BAR@ ZOO

$ awk '
BEGIN {
    str = "foo BAR ZOO"
    res = gensub(/[A-Z]+/, "@&@", 2, str)      # how : 2
    print res
}'
foo BAR @ZOO@

$ awk '
BEGIN {
    str = "foo BAR ZOO"
    res = gensub(/[A-Z]+/, "@&@", "g", str)    # how : "g"
    print res
}'
foo @BAR@ @ZOO@
.........................................................

# target 스트링이 주어지지 않으면 입력값으로는 $0 가 사용되지만
# 출력값은 $0 에 대입되지 않으므로 직접 대입해 사용해야 합니다.
$ echo foo BAR ZOO | awk '{
    $0 = gensub(/[A-Z]+/, "@&@", "g")
    print
}'
foo @BAR@ @ZOO@

( ) subexpression 을 이용한 back-reference 를 사용할 수 있습니다.

$ awk '                                      
BEGIN {
    str = "XXX YYY"
    res = gensub(/([A-Z]+) ([A-Z]+)/, "\\2 \\1", "g", str)
    print res
}'
YYY XXX
..........................................................

# 매칭이 되면 값에서 @...@ 가 분리되지만 
$ awk 'BEGIN { str = "@foo@"; print gensub( /^@(.*)@$/, "\\1", "1", str ) }' 
foo

# 매칭이 안되면 원본이 그대로 출력됩니다.
$ awk 'BEGIN { str = "bar"; print gensub( /^@(.*)@$/, "\\1", "1", str ) }' 
bar

한가지 주의할 점은 /.../ 매칭에 포함되지 않는 스트링은 함께 출력된다는 점입니다. 다음의 경우 스트링에서 숫자 부분만 추출하려고 한 것인데 실제 결과는 앞의 공백이 함께 출력됩니다.

$ echo "   123ABC" | awk '{ print "X" gensub( /([0-9]+)[A-Z]+/, "\\1","g") "X" }'
X   123X

# 다음과 같이 스트링 전체를 매칭해야 ( ) 부분만 추출됩니다.
$ echo "   123ABC" | awk '{ print "X" gensub( /\s*([0-9]+)[A-Z]+/, "\\1","g") "X" }'
X123X

match ( string, regex [, array ] )

첫 번째 매칭 되는 스트링의 포지션을 반환합니다. 매칭 되는 스트링이 없을 경우는 0 이 반환됩니다. 이 함수는 또한 RSTARTRLENGTH 변수를 설정합니다. regex 에 ( ) 를 사용하고 array 인수를 사용하면 실제 매칭 된 스트링 값이 array 변수에 설정됩니다.

매칭 될 경우 매칭이 안될 경우
RSTART 해당 포지션 0
RLENGTH 매칭 스트링 length -1

인수에 사용된 regex 과 string 순서가 sub 함수와 다른데 ~ 연산자를 생각하시면 됩니다. $0 ~ /bar+/

$ echo fooXXXbarrr |
awk '{ 
    where = match($0, /bar+/)
    print where, RLENGTH
    print RSTART, RLENGTH
}'
7 5
7 5

regex 에 ( ) 를 사용하면 array 값을 사용할 수 있습니다. array 에는 실제 매칭된 스트링과 start, length 값이 설정됩니다.

$ echo fooXXXbarrr |
awk '{ 
    where = match($0, /(bar+)/, arr)
    print arr[1], where, RLENGTH
    print arr[1], RSTART, RLENGTH
    print arr[1], arr[1, "start"], arr[1, "length"]
}'
barrr 7 5
barrr 7 5
barrr 7 5

$ echo fooXXXbarrr |
awk '{ 
    match($0, /(fo+).+(bar*)/, arr)
    print arr[1], arr[1, "start"], arr[1, "length"]
    print arr[2], arr[2, "start"], arr[2, "length"]
}'
foo 1 3
barrr 7 5

사용 예제 )

# 파일명과 디렉토리명 구하기
$ echo 'aaa/bbb/README.md' |  awk '{print substr($0,match($0,/[^/]+$/))}'
README.md

$ echo 'aaa/bbb/README.md' |  awk '{print substr($0,1,match($0,/[^/]+$/)-2)}'
aaa/bbb
--------------------------------------------------

# regex 매칭 스트링을 같은 length 의 space 로 치환
$ cat file
VBoxManage natnetwork       add --netname <name>
VBoxManage natnetwork       remove --netname <name>
VBoxManage natnetwork       modify --netname <name>

$ awk -v str="VBoxManage natnetwork" '
{ if (match($0, str)){ sub(str, sprintf("%*s", RLENGTH,"")); print }}' file
                            add --netname <name>
                            remove --netname <name>
                            modify --netname <name>

split ( string, fields [, fieldsep [, seps ] ] )

아래와 같은 str 이 있을 경우 /@[A-Z]+@/ 를 field separator 로 잡고 split 하게 되면 (hello ) (, this is a ) ( end.) 가 fields 가 되고 (@AAA@) (@BBB@) 가 separators 가 됩니다.

필드 개수가 반환되고 전체 flds 와 seps 값을 합치면 str 이 됩니다.

$ awk -f - <<\EOF
BEGIN { 

    str = "hello @AAA@, this is a @BBB@ end."

    num = split (str, fld, /@[A-Z]+@/, sep)    # fld 와 sep 은 array 가 됩니다.
    print "number of flds : " num
    for ( i in fld )
        printf "%s. fld: (%s) \t sep: (%s)\n", i, fld[i], sep[i]
}
EOF
number of flds : 3
1. fld: (hello )         sep: (@AAA@)
2. fld: (, this is a )   sep: (@BBB@)
3. fld: ( end.)          sep: ()

patsplit ( string, fields [, fieldpat [, seps ] ] )

이 함수는 split 함수와 비슷하지만 다른 점은 FPAT 을 이용해 필드를 추출하는 것처럼 필드를 분리합니다. 따라서 /@[A-Z]+@/ 가 field pattern 이 되어 매칭된 (@AAA@) (@BBB@) 가 필드가 되고 (hello ) (, this is a ) ( end.) 가 separators 가 됩니다. 한가지 참고할 것은 첫 번째 필드값 (@AAA@) 앞에 위치한 (hello ) 는 sep index 가 0 이 됩니다.

필드 개수가 반환되고 전체 seps 와 flds 값을 합치면 str 이 됩니다.

$ awk -f - <<\EOF
BEGIN { 

    str = "hello @AAA@, this is a @BBB@ end."

    num = patsplit(str, fld, /@[A-Z]+@/, sep)   # fld 와 sep 은 array 가 됩니다.
    print "number of flds : " num
    printf "\t \tsep: (%s)\n", sep[0]           # sep index 가 0
    for ( i in fld )                                            
        printf "%s. fld: (%s) sep: (%s)\n", i, fld[i], sep[i] 
}
EOF
number of flds : 2
                sep: (hello )
1. fld: (@AAA@) sep: (, this is a )
2. fld: (@BBB@) sep: ( end.)

substr ( string, start [, length ] )

start 포지션과 length 를 이용하여 원하는 스트링을 추출할 수 있습니다.
C 언어에서와는 달리 첫 번째 문자의 포지션 값은 1 입니다.

$ awk 'BEGIN { str="abcdef"; print substr(str, 2, 3) }'
bcd

$ awk 'BEGIN { str="abcdef"; print substr(str, 2) }'
bcdef

$ echo "hello world" | awk '{ print substr($0, 1, 5) " 123 " substr($0, 7) }'
hello 123 world

sub, gsub 함수의 경우 함수 실행 결과가 다시 target 스트링에 대입되기 때문에 target 스트링에 substr 함수를 사용할 수 없습니다. 하지만 gensub 함수는 사용할 수 있습니다.

# gensub 함수 에서는 target 스트링에 substr 함수를 사용할 수 있습니다.
$ echo "hello world" | awk '{ print gensub( /l/, "X", "g", substr($0, 1, 5)) }'
heXXo

index ( in, find )

매칭 되는 스트링의 포지션을 구할 때 사용합니다.
매칭 되는 스트링이 없을 경우 0 이 반환됩니다.

$ awk 'BEGIN { print index("peanut", "pea") }'
1

$ awk 'BEGIN { print index("peanut", "nu") }'
4
............................................

$ sudo awk -b -v RS='^$' '{ print index($0, "\037\213\010") }' /boot/vmlinuz-4.13.0-39-generic
18357

length ( [ string ] )

length 함수는 scalar 변수와 array 변수에서 각각 다르게 적용됩니다. scalar 변수에서는 string length 가 되고 array 변수에서는 array length 가 됩니다. string 값이 주어지지 않으면 $0 값이 사용됩니다.

$ awk 'BEGIN { print length("peanut") }'
6

# string 값이 주어지지 않으면 `$0` 값이 사용됩니다.
$ echo "peanut" | awk '{ print length() }'
6

# 15 * 35 = 525 이므로 length 는 3 이 된다.
$ awk 'BEGIN { print length(15 * 35) }'
3

strtonum ( string )

숫자가 0 으로 시작하면 8 진수로, 0x ( 0X ) 로 시작하면 16 진수로 인식이 되는데요. 그런데 입력 스트림이나 -v 옵션에 의해 외부로부터 값이 전달되는 경우는 기본적으로 모두 스트링으로 취급되므로 10 진수와 달리 정상적으로 연산이 되지 않습니다. 이때 사용할 수 있는 함수입니다.

# 스크립트 내에서 직접 8, 16 진수를 사용할 때는 정상적으로 연산이 된다.
$ awk 'BEGIN { print 011; print 011 + 1 }'
9
10

$ awk 'BEGIN { print 0x11; print 0x11 + 1 }'
17
18

# 외부에서 값이 전달될 때는 스트링이 되므로 정상적으로 연산이 되지 않는다.
$ echo 011 | awk '{ print $1; print $1 + 1 }'
011
12

$ echo 0x11 | awk '{ print $1; print $1 + 1 }'
0x11
1

# 이때 strtonum 함수를 사용할 수 있습니다.
$ echo 011 0x11 | awk '{ print strtonum($1) + 1; print strtonum($2) + 1 }'
10
18

sprintf ( format, expression1, ... )

sprintf 함수는 포멧 출력값을 변수로 저장할 때 사용합니다.

$ awk 'BEGIN { pi = sprintf("pi = %.2f", 22/7); print pi }'
pi = 3.14

tolower ( string )

대문자를 소문자로 변환합니다.

$ awk 'BEGIN { print tolower("MiXeD cAsE 123") }'
mixed case 123

toupper ( string )

소문자를 대문자로 변환합니다.

$ awk 'BEGIN { print toupper("MiXeD cAsE 123") }'
MIXED CASE 123

asort ( source [, dest [, how ] ] )

해당 페이지 참조

asorti ( source [, dest [, how ] ] )

해당 페이지 참조