본문 바로가기

IT

[Ubuntu/Linux] 쉘스크립트 변수의 모든 것

쉘스크립트에서 변수를 빼먹으면 안되죠~

어쩌면 가장 먼저 다뤄야했을 내용일지도 모르겠네요.

워낙 두서없이 생각나는 순서로 정리하다보니 뒤로 미뤄졌습니다.

하지만 그렇다고 해서 그 우선순위에서 밀린다는 얘기는 절대로 아닙니다.



변수명은 영문자, 숫자 그리고 '_'(underscore)로만 이뤄집니다.

그 외의 문자는 변수명으로 인식하지 못합니다.

따라서 $FILE.old라는 문장에서 $FILE만이 변수명이 될 수 있습니다.

".old"부터는 "." 때문에 변수명이 될 수 없습니다.

그저 변수명 뒤에 연달아 나온 스트링으로 인식됩니다.


$ touch secret
$ FILE=secret
$ mv $FILE $FILE.old
$ ls secret*
secret.old

위의 예에서는 먼저 secret란 파일을 만든 후,

$FILE 변수를 사용하여 secret.old로 파일이름을 바꿉니다.

변수명과 '.old' 사이에 빈칸이 없어도,

'.'이 변수명의 범주에 들지 않기 때문에 '.' 뒤부터는 자연스레 스트링으로 인식됩니다.

다른 고급언어에서는 이와 같은 상황에서 에러를 출력하지만,

쉘스크립트에서는 이런 모호함도 처리해주네요.


이와는 대조적으로 '.' 대신 '_'를 사용하면 모두 변수명이 됩니다.

$ mv $FILE $FILE_new
mv: `secret' 다음에 대상 파일 명령이 누락

위처럼 $FILE_new는 'FILE_new'라는 이름의 변수일 뿐입니다.

변수에는 아무것도 넣어져 있지 않기 때문에 NULL입니다.

그래서 명령이 누락되었다는 메시지가 나오지요.


굳이 $FILE 변수값에 '_'가 포함된 스트링을 덧붙이고 싶다면,

아래에 명시된 방법 중에 하나를 사용하면 됩니다.

mv $FILE $FILE"_new"
mv $FILE $FILE'_new'
mv $FILE $FILE""_new
mv $FILE $FILE''_new
mv $FILE "$FILE"_new


큰따옴표를 변수명쪽에 붙이든 스트링쪽에 붙이든 결과는 같습니다.

흥미로운건 변수명과 스트링 사이에 따옴표를 넣어도 결과는 같다는 것이겠죠?

왜 그런걸까요?

""는 고급언어처럼 스트링을 나타내는 상징이 아닙니다.

스크립트에서는 ""는 따옴표 안에 있는 요소를 그룹으로 묶는 기능이 있습니다.

따옴표 안으로 넣어 그룹이 되면 그 밖의 요소는 그룹에 속하지 않은 요소가 됩니다.

좌우도 구분지어지겠지요.


mv $FILE $FILE\_new

'\'는 escape 문자처럼 동작하는데요,

변수와 스트링을 구분할 때도 사용됩니다.

변수명 뒤에 오는 '\'는 영문이나 숫자 혹은 '_'가 아니기 때문에 변수명이 될 수 없습니다.

그렇다면 당연히 변수명은 '\' 앞글자까지겠죠.

$ echo "\_str"
\_str
$ echo '\_str'
\_str


일반적으로 큰따옴표나 작은따옴표로 "\_"를 출력하면 역슬래시도 그대로 나옵니다.

왜냐하면 "_"는 escape 없이도 표현할 수 있는 문자이기 때문입니다.

하지만, 따옴표 없이 "\_"를 출력하면, 역슬래시는 없어지고 "_"만 출력됩니다.

비단 '_' 뿐만 아니라 어떤 글자가 와도 역슬래시는 표시되지 않습니다.


쉘단에서 따옴표 없는 \는 다음 문자를 연속되는 문자로 취급되게 해줍니다.

곧 변수명이 치환된 후에 이어서 오는 문자열과 자연스럽게 합쳐지지요.

$ echo \_str
_str
$ echo \+
+
$ echo \-
-
$ echo \a
a


변수명을 보다 확실하게 확정짓는 방법이 있습니다.

변수명 좌우로 괄호 {, }를 치면 됩니다.

괄호영역 내에 있는 이름이 변수명이 됩니다.

mv $FILE ${FILE}_new


이상으로 변수명에 대해 전반적으로 훑어보았습니다.

이제는 변수값을 지정하는 여러가지 방법에 대해 따져보겠습니다.


괄호에는 단지 변수명만 들어가지 않습니다.

$ cat ${NO_VARIABLE? No variable}
bash: NO_VARIABLE:  No variable
$ echo $?
1

위처럼 변수명이 정의되지 않았을때 물음표 뒤의 문장을 출력할 수 있습니다.

대신 에러(1)가 리턴되므로 조건문/반복문에서 제대로 처리해야합니다.


괄호 안에 '-'가 들어가는 경우도 있습니다.

'-'는 변수가 정의되지 않은 경우에만 적용하라는 의미입니다.

$ echo ${NO_VARIABLE-$HOME}
/home/storycompiler
$ echo $?
0

NO_VARIABLE 변수가 사전에 정의되지 않았다면,

$HOME 값이 대입됩니다.


괄호 안에 '+'를 추가할 수도 있습니다.

'+'는 '-'기호와 반대의미를 가집니다.

'-'가 선언되지 않았을때 사용한다면,

'+'는 선언되었을때 사용합니다.

$ echo ${HOME+"home is set"}
home is set
$ echo $?
0

위의 예에서 $HOME변수가 선언되어 있으면 뒤의 문자열을 출력합니다.


괄호 안에 '='를 사용한다면,

'='의 의미답게 변수에 값이 있든 없든 관계없이 '=' 뒤의 값이 대입됩니다.

$ echo ${NO_VARIABLE=variable}
variable
$ echo ${NO_VARIABLE}
variable


정리하자면,

"?"는 정의되어 있지 않으면 뒤의 문자열을 출력하고,

"+"는 정의 되어 있어야 뒤의 문자열을 출력합니다.


"-"는 정의되어 있지 않으면 뒤의 문자열을 대입하고,

"="는 "-"와 동일합니다.

대입과 출력의 차이가 있습니다.


'?', '-', '+', '=' 앞에 ':' 문자를 사용할 수도 있습니다.

':' 문자는 null로 define 된 경우까지 추가하여 각 연산을 강화합니다.


$ A=""
$ echo ${A? "undefined"}

$ echo ${A:? "undefined or null"}
bash: A:  undefined or null


위와 같이 A에 ""를 대입하면, 변수 A는 defined 상태입니다.

따라서 ${A? "undefined"}에서 "undefined" 문자열을 출력하지 않지요.

하지만 ':'를 붙이게 되면, null로 정의된 경우도 검출이 됩니다.

곧, ?는 정의되지 않으면 출력하지만,

:?는 정의되지 않은 것 뿐만 아니라 null로 정의되더라고 출력합니다.


"+"는 정의된 경우에만 문자열을 출력했다면,

":+"는 null이 아닌 값이 정의되어 있는 경우에만 문자열을 출력합니다.


"-"는 정의되어 있지 않으면 문자열을 대입했지만,

":-"는 변수에 값이 정의되지 않았거나 null로 대입된 경우에 뒤의 문자열을 대입합니다.

":="는 ":-"와 동일합니다.


$ echo ${A+"defined"}
defined
$ echo ${A:+"defined"}
(공백)


"+"의 경우, A가 정의되어 있으면 defined를 출력합니다.

":+"의 경우, null로 정의되어 있기 때문에 ":+" 뒤의 문자열을 출력하지 않습니다.


이상으로 변수에 대한 이야기를 마치겠습니다.

그럼 좋은 하루 보내세요~

끝_




* References

http://bash.cyberciti.biz/guide/Rules_for_Naming_variable_name