expr

이 명령은 외부 명령인데요. bash 의 경우 [[ ]] 특수 명령과 매개변수 확장 기능을 통해 shell 변수를 이용한 regex 매칭, substr 같은 기능을 기본적으로 사용할 수 있습니다. 하지만 sh 의 경우는 그런 기능을 제공하지 않기 때문에 외부 명령을 사용해야 하는데요 이때 사용할수 있는 명령이 expr 입니다. expr 는 보통 산술연산을 하는 명령으로 알고 있는데 sh 에서 사용할수 있도록 다음과 같은 유용한 기능을 제공합니다.

regex 매칭

매칭에는 Basic Regular Expressions 을 사용하므로 다음과 같은 regex 메타문자를 사용할 때는 escape 해야 합니다.

?, +, ( ), { }, |

regex 매칭은 다음과 같이 두 가지 형태로 사용할 수 있습니다.

expr STRING : REGEX
expr match STRING REGEX

실행시 기본적으로 매칭 되는 문자 수를 stdout 으로 출력하므로 필요하지 않을 경우 /dev/null 로 redirection 하면 됩니다.

$ AA="foo 12345 bar"

# 기본적으로 매칭 되는 문자 수를 stdout 으로 출력
$ expr "$AA" : "foo [0-9]\+"
9

$ expr "$AA" : "foo [0-9]\+" > /dev/null
$

# if 문에서 다음과 같이 사용할 수 있습니다.
$ if expr "$AA" : "foo [0-9]\+" > /dev/null
     then echo Yes
     else echo No
fi
Yes

한가지 참고해야 될 사항은 매칭은 앞에서부터 한다는 것입니다. ( ^ anchor 가 기본적으로 사용되는 것과 같습니다. ) 그러므로 다음 첫 번째 경우는 참이지만 두 번째는 거짓이 됩니다.

$ expr "$AA" : "foo [0-9]\+"; echo status : $?      # 참
9
status : 0

$ expr "$AA" : "[0-9]\+ bar"; echo status : $?      # 거짓
0
status : 1

# 따라서 뒷부분을 매칭하려면 다음과 같이 해야 됩니다.
$ expr "$AA" : ".*[0-9]\+ bar"; echo status : $?
13
status : 0

보통 변수와 regex 스트링 앞에 문자 X 를 두어서 많이 작성합니다. 이것은 뒷부분에도 나오지만 $AA 변수값이 expr 명령에서 사용되는 키워드일 경우 오류가 발생하는 것을 방지하기 위한 방법이기도 합니다.

$ if expr "X$AA" : "X.*[0-9]\+ bar" > /dev/null
     then echo Yes
     else echo No
fi
Yes

\( \) 을 이용해서 매칭 되는 부분만 뽑을 수 있습니다.

$ expr "X$AA" : "Xfoo \([0-9]\+\)"
12345

$ BB=$(expr "X$AA" : "Xfoo \([0-9]\+\)")

$ echo $BB
12345

length

스트링의 length 를 반환합니다.

length STRING

$ AA=1234567890

$ expr length "$AA"
10

index

스트링에서 CHARS 위치를 반환합니다.

index STRING CHARS

$ AA="value=12345"

$ expr index "$AA" "="
6

# 두 개 이상의 CHARS 를 사용할 경우 처음에 매칭 되는 위치가 반환됩니다.
$ AA="foo:bar=123"

$ expr index "$AA" "=:"
4

substr

스트링에서 postion 과 length 를 이용해 특정 부분을 추출합니다.

substr STRING POS LENGTH

$ AA="value=12345"

$ idx=$(expr index "$AA" "=")
$ len=$(expr length "$AA")
$ expr substr "$AA" $(( idx + 1 )) $(( len - idx ))
12345

+ 문자의 사용

"match", "length", "index", "substr" 는 expr 명령의 키워드 인데요. 동일한 스트링이 변수 값으로 사용되면 expr 명령이 구분할 수 없으므로 오류가 발생합니다. 이때는 앞에 + 문자를 붙여주어 문제를 해결할 수 있습니다.

# 변수의 값이 expr 명령의 키워드와 동일한 "length"
$ AA=length

$ expr "$AA" : "len[a-z]\{3\}"
expr: syntax error

# 앞에 '+' 붙여 문제 해결
$ expr + "$AA" : "len[a-z]\{3\}"
6
# 또는
$ expr "X$AA" : "Xlen[a-z]\{3\}"
7

# 변수의 값이 expr 명령의 키워드와 동일한 "match"
$ AA=match

$ expr length "$AA"
expr: syntax error

$ expr length + "$AA"
5

# "--" 스트링의 경우
$ AA="--"

$ expr "$AA" : "-[0-9]$\|-$\|--$"; echo status : $?  
expr: syntax error
status : 2

$ expr + "$AA" : "-[0-9]$\|-$\|--$"; echo status : $?  
2
status : 0

# 또한 '+' 문자를 사용할 때도 앞에 '+' 를 붙여야 한다.
$ AA="foo+bar"

$ expr index "$AA" "+"
expr: syntax error

$ expr index "$AA" + "+"
4

따라서 변수와 + 문자 앞에는 기본적으로 + 를 붙여 사용하는 것도 오류를 줄일 수 있는 방법입니다.