쿼우팅이란 문자열을 따옴표로 묶는 것을 말합니다. 이렇게 하는 이유는 문자열 안에 특수 문자가 들어가 있을 경우, 쉘이나 쉘 스크립트에 의해 그 특수 문자가 재해석이나 확장되는 것을 방지하기 위해서 입니다.(어떤 문자가 가진 글자 그대로의 뜻과는 다른 해석이 가능한 문자를 "특수 문자"라고 합니다. 예를 들면, 와일드 카드 문자인 *가 특수 문자입니다.)
bash$ ls -l [Vv]* -rw-rw-r-- 1 bozo bozo 324 Apr 2 15:05 VIEWDATA.BAT -rw-rw-r-- 1 bozo bozo 507 May 4 14:25 vartrace.sh -rw-rw-r-- 1 bozo bozo 539 Apr 14 17:11 viewdata.sh bash$ ls -l '[Vv]*' ls: [Vv]*: No such file or directory |
참고: 몇몇 프로그램이나 유틸리티들은 쿼우트된 문자열에 들어 있는 특수 문자를 재해석하거나 확장 시킬 수 있습니다. 이것은 쿼우팅의 중요한 사용법으로써 쉘이 명령어줄 매개변수를 해석하지 않고 프로그램이 해석해서 확장하도록 해 줍니다.
bash$ grep '[Ff]irst' *.txt file1.txt:This is the first line of file1.txt. file2.txt:This is the First line of file2.txt.grep [Ff]irst *.txt 라고 하면 당연히 동작하지 않습니다.
변수를 참조할 때는 보통 큰 따옴표(" ")로 묶어 주는게 좋습니다. 이렇게 하면 $, `(backquote), \(이스케이프)를 제외한 모든 특수 문자들을 보존해 줍니다. 변수에 쿼우트를 걸어서("$variable") $을 특수 문자로 인식하게 되면 그 변수의 값으로 바꿔 줍니다 (위의 예 5-1 참고).
낱말 조각남(word splitting) [1] 을 피하려면 큰 따옴표를 쓰기 바랍니다. 이렇게 하면 인자에 공백문자가 들어 있어도 하나의 낱말로 인식하게 해 줍니다.
variable1="4개의 낱말로 이루어진 변수" COMMAND 이것은 $variable1 입니다. # COMMAND는 6개의 인자를 가지고 실행됩니다. # "이것은" "4개의" "낱말로" "이루어진" "변수" "입니다." COMMAND "이것은 $variable1 입니다." # COMMAND는 1개의 인자를 가지고 실행됩니다. # "이것은 4개의 낱말로 이루어진 변수 입니다." variable2="" # 비어 있습니다. COMMAND $variable2 $variable2 $variable2 # COMMAND는 인자 없이 실행됩니다. COMMAND "$variable2" "$variable2" "$variable2" # COMMAND는 3개의 빈 인자를 가지고 실행됩니다. COMMAND "$variable2 $variable2 $variable2" # COMMAND는 2개의 빈칸을 가진 하나의 인자를 가지고 실행됩니다. # Thanks, S.C. |
작은 정보: echo문의 인자를 큰 따옴표로 묶어주는 것은 낱말 조각남이 문제가 될 때에만 필요합니다.
예 6-1. 이상한 변수를 에코하기
#!/bin/bash # weirdvars.sh: 이상한 변수 에코하기. var="'(]\\{}\$\"" echo $var # '(]\{}$" echo "$var" # '(]\{}$" 차이가 없죠? echo IFS='\' echo $var # '(] {}$" \ 가 빈 칸으로 바뀌었네요. echo "$var" # '(]\{}$" # S.C. 제공 exit 0 |
작은 따옴표(' ')도 큰 따옴표와 비슷하게 동작하지만 $의 특별한 의미를 꺼 버려서 변수 참조가 일어나지 않게 합니다. 작은 따옴표안의 '을 제외한 모든 특수 문자들은 단순히 문자 그대로 해석됩니다. 작은 따옴표("완전한 쿼우팅")를 큰 따옴표("부분 인용")보다 좀 더 엄격한 방법이라고 생각하면 됩니다.
참고: 작은 따옴표안에서는 이스케이프 문자(\)도 글자 그대로 인식되기 때문에 작은 따옴표로 묶인 문자열에 \을 써서 작은 따옴표 자체를 넣으려고 한다면 원하는 결과가 나오지 않습니다.
echo "Why can't I write 's between single quotes" echo # 간접적인 방법 echo 'Why can'\''t I write '"'"'s between single quotes' # |-------| |----------| |-----------------------| # 이스케이프와 큰 따옴표로 쿼우트된 작은 따옴표에 의해 3개의 문자열로 나뉘어져 있습니다. # Stephane Chazelas 제공.
이스케이프(Escaping)는 하나의 문자를 쿼우팅하는 방법입니다. 어떤 문자 앞에 이스케이프 문자(\)가 오면 쉘에게 그 문자를 문자 그대로 해석하게 해 줍니다.
뉴라인(newline)
리턴(return)
탭(tab)
수직탭(vertical tab)
백스페이스(backspace)
"경고"(alert, 비프음이나 깜빡거림)
0xx 같은 8진수 아스키 표현으로 변환
예 6-2. 이스케이프된 문자들
#!/bin/bash # escaped.sh: 이스케이프된 문자들 echo; echo echo "\v\v\v\v" # \v\v\v\v 라고 출력 # 'echo'가 이스케이프된 문자들을 출력하게 하려면 -e 옵션을 써야 됩니다. echo -e "\v\v\v\v" # 4 개의 수직탭 출력 echo -e "\042" # " 출력(따옴표, 8진수 아스키 문자 42). # Bash 버전 2 이후에서는 $'\xxx' 도 허용됩니다. echo $'\n' echo $'\a' echo $'\t \042 \t' # 탭으로 둘려쌓인 따옴표("). # 변수에 아스키 문자를 할당하기. # ------------------------------ quote=$'\042' # " 를 변수로 할당. echo "$quote 여기는 쿼우트된 부분이고, $quote 여기는 안 된 부분입니다." echo # 변수에 아스키 문자를 여러개 쓰기. triple_underline=$'\137\137\137' # 137 은 "_"의 8진수 아스키 코드. echo "$triple_underline 밑줄 $triple_underline" ABC=$'\101\102\103\010' # 101, 102, 103 은 각각 8진수 A, B, C. echo $ABC echo; echo escape=$'\033' # 033 은 이스케이프의 8진수. echo "\"escape\" echoes as $escape" echo; echo exit 0 |
$' ' 문자열 확장의 다른 예제를 보고 싶으면 예 35-1 참고.
큰 따옴표를 그냥 큰 따옴표로 해석
echo "Hello" # Hello echo "\"Hello\", he said." # "Hello", he said. |
달러 표시를 그냥 달러 표시로 해석(\$ 뒤에 오는 변수는 참조되지 않습니다)
echo "\$variable01" # $variable01 이라고 찍힘 |
백슬래쉬를 그냥 백슬래쉬로 해석
echo "\\" # \ 라고 찍힘 |
참고: \ 의 동작은 자신이 이스케이프 됐는지, 쿼우트 됐는지, here document에서 쓰이는지에 따라 달라집니다.
echo \z # z echo \\z # \z echo '\z' # \z echo '\\z' # \\z echo "\z" # \z echo "\\z" # \z echo `echo \z` # z echo `echo \\z` # z echo `echo \\\z` # \z echo `echo \\\\z` # \z echo `echo \\\\\\z` # \z echo `echo \\\\\\\z` # \\z echo `echo "\z"` # \z echo `echo "\\z"` # \z cat <<EOF \z EOF # \z cat <<EOF \\z EOF # \z # Stephane Chazelas 제공.
명령어의 인자 리스트 중간에 나오는 빈칸을 이스케이프 시키면 낱말 조각남을 막을 수 있습니다.
file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7" # 명령어에 넘길 인자(들)의 파일 리스트. # 리스트에 두 개를 더 추가하고 리스트를 보여줌. ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list echo "-------------------------------------------------------------------------" # 빈칸을 이스케이프 시키면 어떤 일이 일어날까요? ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list # 에러: 파일들을 구분 지어줄 빈칸을 이스케이프 시켰기 때문에 # 제일 앞 세개의 파일이 'ls -l' 에게 하나의 인자로 넘어갑니다. |
이스케이프는 한 명령어를 여러줄에 걸쳐 쓸 수 있게도 해 줍니다. 보통은, 줄이 다르면 다른 명령어를 나타내지만 줄 끝에 이스케이프를 걸면 뉴라인 문자를 이스케이프시키기 때문에 그 다음줄이 원래 줄과 한 줄로 이어지게 됩니다.
(cd /source/directory && tar cf - . ) | \ (cd /dest/directory && tar xpvf -) # 다시 보는 알란 콕스의 디렉토리 트리 복사 명령어 # 여기서는 더 읽기 쉽도록 두 줄로 나누었습니다. # 이렇게도 가능하죠: tar cf - -C /source/directory | tar xpvf - -C /dest/directory # 밑의 참고를 보세요. # (Thanks, Stephane Chazelas.) |
참고: 줄이 파이프 문자인 |으로 끝난다면 굳이 이스케이프 문자(\)를 적어줄 필요가 없습니다. 하지만, 여러줄에 걸친 하나의 명령어에서 줄 끝에 항상 이스케이프 문자를 적어주는 것은 아주 좋은 프로그래밍 습관입니다.
echo "foo bar" #foo #bar echo echo 'foo bar' # 아직은 다른점이 없죠. #foo #bar echo echo foo\ bar # 뉴라인이 이스케이프 됐습니다. #foobar echo echo "foo\ bar" # 약한 쿼우트 안에서는 \ 가 이스케이프 문자로 해석되기 때문에 똑같습니다. #foobar echo echo 'foo\ bar' # 강한 쿼우팅 안에서 \ 는 아무 의미 없이 그냥 \ 입니다. #foor\ #bar # Stephane Chazelas 제공. |
[1] | 여기서 "낱말 조각남"은 문자열이 조각나서 여러개의 인자로 인식되는 것을 뜻합니다. |