https://wiki.kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/string-manipulation.html
Bash 는 놀랍도록 많은 문자열 조작 연산을 제공합니다. 하지만 불행하게도 이 도구들은 하나로 통합되어 있지 않습니다. 몇 개는 매개변수 치환의 서브셋이고 다른 것은 유닉스의 expr 명령어의 기능에 해당합니다. 이렇기 때문에 이런 혼동스러움에 대한 언급도 없이 명령어 문법에 일관성이 없고 기능이 중복되어 있습니다.
문자열 길이
- ${#string}
-
- expr length $string
-
- expr "$string" : '.*'
-
stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15 |
문자열 시작에서부터 매칭되는 문자열조각(substring)의 길이
- expr match "$string" '$substring'
$substring 은 정규 표현식입니다.
- expr "$string" : '$substring'
$substring 은 정규 표현식입니다.
stringZ=abcABC123ABCabc
# |------|
echo `expr match "$stringZ" 'abc[A-Z]*.2'` # 8
echo `expr "$stringZ" : 'abc[A-Z]*.2'` # 8 |
인덱스
- expr index $string $substring
$string 에서 일치하는 $substring 의 첫 문자의 위치.
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12` # 6
# C 의 위치.
echo `expr index "$stringZ" 1c` # 3
# 'c' (3번째 위치에 있는) 가 '1' 보다 먼저 일치됨. |
C 의 strchr()와 거의 비슷합니다.
문자열조각 추출(Substring Extraction)
- ${string:position}
$string 의 $position 부터의 문자열조각을 추출.
string 매개변수가 "*" 이거나 "@" 라면 position에서 시작하는 위치 매개변수 [1] 를 추출해 냅니다.
- ${string:position:length}
$string의 $position부터 $length만큼의 문자를 추출해 냅니다.
stringZ=abcABC123ABCabc
# 0123456789.....
# 0 부터 시작하는 인덱싱.
echo ${stringZ:0} # abcABC123ABCabc
echo ${stringZ:1} # bcABC123ABCabc
echo ${stringZ:7} # 23ABCabc
echo ${stringZ:7:3} # 23A
# 3글자짜리 문자열조각. |
string 매개변수가 "*" 나 "@" 라면 위치 position에서 시작하는 매개변수의 최대 length를 추출해 냅니다.
echo ${*:2} # 두번째 이후의 위치 매개변수를 에코.
echo ${@:2} # 위와 같음.
echo ${*:2:3} # 2,3,4번(3개) 위치 매개변수를 에코. |
- expr substr $string $position $length
$string의 $position부터 $length만큼의 문자를 추출해 냅니다.
stringZ=abcABC123ABCabc
# 123456789......
# 1 부터 시작하는 인덱싱.
echo `expr substr $stringZ 1 2` # ab
echo `expr substr $stringZ 4 3` # ABC |
- expr match "$string" '\($substring\)'
$string의 처음에서부터 정규 표현식인 $substring을 추출해 냅니다.
- expr "$string" : '\($substring\)'
$string의 처음에서부터 정규 표현식인 $substring을 추출해 냅니다.
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
# 위의 두 가지 형태는 동일합니다. |
문자열조각 삭제(Substring Removal)
- ${string#substring}
$string의 앞 부분에서부터 가장 짧게 일치하는 $substring을 삭제.
- ${string##substring}
$string의 앞 부분에서부터 가장 길게 일치하는 $substring을 삭제.
stringZ=abcABC123ABCabc
# |----|
# |----------|
echo ${stringZ#a*C} # 123ABCabc
# 'a'와 'C' 사이에서 가장 짧게 일치되는 부분을 삭제.
echo ${stringZ##a*C} # abc
# 'a'와 'C' 사이에서 가장 길게 일치되는 부분을 삭제. |
- ${string%substring}
$string의 뒷 부분에서부터 가장 짧게 일치하는 $substring을 삭제.
- ${string%%substring}
$string의 뒷 부분에서부터 가장 길게 일치하는 $substring을 삭제.
stringZ=abcABC123ABCabc
# ||
# |------------|
echo ${stringZ%b*c} # abcABC123ABCa
# $stringZ의 뒷 부분부터 계산해서 'b'와 'c' 사이에서 가장 짧게 일치하는 부분을 삭제.
echo ${stringZ%%b*c} # a
# $stringZ의 뒷 부분부터 계산해서 'b'와 'c' 사이에서 가장 길게 일치하는 부분을 삭제. |
예 9-9. 그래픽 파일을 다른 포맷 확장자로 이름을 바꾸면서 변환
#!/bin/bash
# cvt.sh:
# 특정 디렉토리의 모든 MacPaint 이미지 파일을 "pbm" 포맷으로 변환.
# Brian Henderson(bryanh@giraffe-data.com)이 관리하고 있는 "netpbm" 패키지의
#+ "macptopbm" 을 사용함.
# Netpbm 은 거의 대부분의 리눅스 배포판에 포함되어 있습니다.
OPERATION=macptopbm
SUFFIX=pbm # 새 파일이름 확장자.
if [ -n "$1" ]
then
directory=$1 # 디렉토리 이름이 인자로 주어질 경우...
else
directory=$PWD # 아니면 현재 디렉토리에 대해서.
fi
# 대상 디렉토리의 모든 파일을 ".mac" 확장자의 MacPaint 이미지 파일이라고 가정.
for file in $directory/* # 파일이름 globbing.
do
filename=${file%.*c} # 파일이름에서 ".mac" 확장자를 떼어냄
#+ ('.*c' 는 '.' 과 'c'를 포함해서 둘 사이의
#+ 모든 것과 일치함).
$OPERATION $file > $filename.$SUFFIX
# 변환된 파일을 새 파일이름으로 재지향.
rm -f $file # 변환후 원래 파일 삭제.
echo "$filename.$SUFFIX" # 결과를 표준출력으로 로깅.
done
exit 0 |
문자열 조각 대치(Substring Replacement)
- ${string/substring/replacement}
처음 일치하는 $substring을 $replacement로 대치.
- ${string//substring/replacement}
일치하는 모든 $substring을 $replacement로 대치.
stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
# 처음 일치하는 'abc'를 'xyz'로 대치.
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
# 일치하는 모든 'abc'를 'xyz'로 대치. |
- ${string/#substring/replacement}
$substring이 $string의 맨 앞에서 일치하면 $replacement로 대치.
- ${string/%substring/replacement}
$substring이 $string의 맨 뒤에서 일치하면 $replacement로 대치.
stringZ=abcABC123ABCabc
echo ${stringZ/#abc/XYZ} # XYZABC123ABCabc
# 맨 앞에서 일치하는 'abc'를 'xyz'로 대치.
echo ${stringZ/%abc/XYZ} # abcABC123ABCXYZ
# 맨 뒤에서 일치하는 'abc'를 'xyz'로 대치. |
스크립트에서 문자열 조작에 대한 더 자세한 사항은 9.3절와 expr 명령어에서 문자열 조작과 관련된 부분을 참고하세요. 스크립트 예제는 다음을 참고하세요.
예 12-6
예 9-11
예 9-12
예 9-13
예 9-15
-------------------------------------------------------------------------------------------------------------------------
http://cybercafe.tistory.com/330
쉘에서 문자열 자르기를 설명하기 전에 쉘에서의 변수의 특징을 먼저 알아 보자.
일반적인 Java나 C와 같은 프로그래밍 언어에서는 변수의 선언과 타입(type)이 무척 중요하다. 선언하지 않고 사용하거나 잘못 참조하거나 잘못 연산하게 되면 엉뚱한 값이 출력되거나 컴파일 시 에러를 팍팍~뿌려댄다. 하지만 쉘스크립트에서는 변수는 선언하지 않으며 타입을 지정하지 않고 사용해도 된다.
이따금씩 쉘 스크립트를 짜다보면 문자열과 숫자의 취급이 헷갈리곤 한다. C언어나 Java언어에서는 변수에 저장될 값이 숫자냐 문자냐를 무척 따져 형변환을 안해주게 되면 가차없이 컴파일 시 에러를 뿌려주는데 반해 쉘 스스크립트는 거침없이 알아서 연산을 한다.
아래 두 스크립트를 비교해보자.
a=10
b=10
let c=a+b
echo $a+$b=$c --> 출력결과 : 10+10=20
c=$a$b
echo $c --> 출력결과 : 1010
변수 a,b에 10이라는 숫자가 저장된 것으로 생각하겠지만 변수 a와 b는 숫자형으로도 사용이 가능하고 문자열로도 사용이 가능하다. 즉 산술연산식에 변수를 사용하면 숫자로 인식되어 계산되고 문자열 연산에 사용되면 문자열로 인식되어 합쳐지게 된다. 또한 연산의 결과를 받는 변수 c도 연산의 결과에 따라 숫자로 사용되기도 하고 문자로 사용되기도 한다.
아래의 스크립트도 앞의 스크립트와 같은 결과를 보여준다.
a="10"
b="10"
let c=a+b
echo $a+$b=$c --> 출력결과 : 10+10=20
c=$a$b
echo $c --> 출력결과 : 1010
변수 a와 b의 초기화에 큰따옴표(")가 사용되어 언뜻 문자열로 사용될 것 같지만 연산식에 따라 숫자로도, 문자열로도 그때 그때 알아서(?) 쉘이 연산을 해준다.
쉘에서 변수의 특징을 이해하였다면 문자열 자르기로 넘어가자.
많은 스크립트 언어와 컴파일 언어에서는 문자열을 합치고 자르는 다양한 이해하기 쉬운 함수를 제공한다. 하지만 쉘에서는 조금 어렵다. 아니 어렵다기보다는 설명이 없이는 난해하다.
자릿수에 의한 문자열 자르기
${var:start:length}
| var : 문자열이 포함된 변수
start : 변수로부터 잘라낼 문자의 시작 번호 (0부터 시작됨)
length : start부터의 잘라낼 문자 갯수. length가 기술되지 않으면 끝까지.
|
예제 :
IP="192.168.100.10"
echo "IP : "$IP
echo "12 to 2 : "${IP:12:2}
예제는 위의 하나로 충분하다고 본다.
IP라는 변수에 저장된 문자열 중에서 13번째 부터 2개의 문자열을 잘라내겠다는 의미다. 13번째인데 12가 쓰인 이유는 잘라내기 시작할 start는 0에서 부터 시작하기 때문이다. 일반적인 상식에서는 1이 숫자의 시작으로 생각하겠지만 프로그래밍에서 숫자의 시작은 0인 경우가 많다.
패턴(구분자) 의한 문자열 자르기
${var%pattern}
| 문자열 변수 var의 끝에서 부터 pattern을 찾아 첫번째로 나타나는 패턴 문자열을 버린다.
|
${var%%pattern}
| 문자열 변수 var의 끝에서 부터 pattern을 찾아 마지막으로 나타나는 패턴 문자열을 버린다.
|
${var#pattern}
| 문자열 변수 var의 앞에서부터 pattern을 찾아 첫번째로 나타나는 패턴 문자열을 버린다.
|
${var##pattern}
| 문자열 변수 var의 앞에서부터 pattern을 찾아 마지막으로 나타나는 패턴 문자열을 버린다.
|
음...이해가 쉽게 된다면 당신에게 경의를 표한다. -.- 내 머리는 나빠서인지 왜 이렇게 난해한 기호들을 나열하여 만들었는지 쉘이나 펄을 만든 이들에게 경외심마저 생긴다.
${ } 는 중괄호{ } 안의 문자열을 처리를 수행하는 연산식이라는 것을 의미한다.
var는 문자열이 저장된 변수다.
%와 #는 변수(var)에서 pattern을 찾기 시작하는 위치다. %는 문자열의 끝에서부터 pattern을 찾기 시작하며 #은 문자열의 처음부터 pattern을 찾기 시작한다.
pattern 은 잘라낼 패턴이다.
가장 중요한 것은 pattern인데..... 여기가 좀 헷갈릴 수 있다. 예제를 보자.
[taeho@ncsd shell]$ cat str.sh
IP="192.168.100.10"
echo "IP : "$IP
echo ${IP%.*}
[taeho@ncsd shell]$ ./str.sh
IP : 192.168.100.10
192.168.100
가장 뒷부분을 잘라내서 버린다는 의미에서 패턴에 %를 사용했다.
다음과 같이 문자열을 자를 때 패턴으로 사용될 구분자는 .(마침표) 로 지정했다.
와일드카드로 *을 사용했다. 즉 . 으로 시작하는 문자열 패턴이라는 의미에서 .* 인 것이다.
${IP%.*}
192.168.100.10 에서 .으로 시작하는 문자열 패턴을 찾아 가장 마지막 패턴을 포함하는 문자들을 잘라내 버리는 것이다.
%를 두번쓰면 즉 %%를 사용하면 반대로 처음으로 .* 패턴이 나타나는 부분부터 끝까지를 버린다.
[taeho@ncsd shell]$ cat str.sh
IP="192.168.100.10"
echo "IP : "$IP
echo ${IP%%.*}
[taeho@ncsd shell]$ ./str.sh
IP : 192.168.100.10
192
[taeho@ncsd shell]$
pattern에서 %와 #의 차이는 패턴을 찾기 시작하는 문자열의 위치라고 앞에서 이야기했다.
일반적인 문자열이라면 %와%% #과 ##을 써서 동일한 결과를 뽑아낼 수 있지만 특이한 문자열 (예를 들면 맨 앞에 구분자로 사용할 특수문자(/,.| 등)가 있는 경우도 있고 없는 경우도 있을 경우...) 의 경우에는 구별하여 사용해야 한다.
정확한 의미를 이해하려면 여러가지 경우로 테스트해보기 바란다.