출처: www.shellscript.sh/first.html

최근 Bash shell의 필요성을 느껴서 shell script를 다시 공부할 필요성을 느꼈습니다. 그래서 당분간 위 출처 내용을 기반으로 한 Bourne shell 공부 내용을 적도록 하겠습니다. 총 1장에서 17장까지 있는 튜토리얼인데, 필요한 부분 중심으로 정리해나갈 예정입니다. 내용을 그대로 번역하는 느낌이 중심이 될 것 같습니다. 전문 번역가가 아니고, 퇴고를 깔끔하게 거치진 않을 것이므로 다소 문장이 직역투거나 오역이 있을 수 있습니다. 그리고 곁가지 설명은 번역하지 않고 넘어갈 수도 있음을 알려드립니다. 퇴고를 거치지 않고 올린 글이라 추후 수정될 수 있음을 알려드립니다.

1장 2장 생략

3장 First Script 요약

파일명 #! First.sh

1 #!/bin/sh
2 #This is a comment!
3 echo Hello World       #This is a comment, too!

첫번째 라인은 유닉스(또는 리눅스)에게 이 파일은 /bin/sh을 통해서 실행될 것임을 알려주는 역할을 합니다. 해당 경로는 unix 시스템에서 bourne shell이 위치하는 디폴트 로케이션입니다. 만약 GNU/Linux라면 /bin/sh가 bash에 심볼릭 링크되어 있을 수도 있습니다. (또는 더욱 최근이라면 dash로 심볼릭 링크)

두번쨰 줄은 말그대로 코멘트입니다. # 이후에 써지는 부분은 실행되지 않고 무시됩니다. 유일한 예외는 #!로 시작하는 첫번째 줄입니다. 이것은 당신이 csh을 사용하든 ksh을 사용하든 Bourne shell에 의해 해석되어야 한다고 명령하는 것입니다. 즉 Bourne shell 프로그래밍을 할 때, 우리는 파일의 첫머리에 꼭 #!/bin/sh을 붙여야하는 것이죠. 세번째 줄에선 echo 커맨드를 실행합니다. 두 개의 패러매터가 있습니다. 첫번째 것은 Hello, 두번째 것은 World입니다. echo는 자동적으로 싱글 스페이스를 두 파라매터 사이에 넣고 있음에 유념하시길 바랍니다. 세번째 줄 뒷부분에 있는 #는 두번째 줄과 마찬가지로 코멘트입니다. # 뒤의 내용은 무시됩니다. 이제 chmod 755 first.sh 를 통해 해당 텍스트 파일을 실행가능한 상태로 만듭니다. 그리고 ./first.sh을 실행합니다. 실제 Shell 스크립트 코드가 아니라 커맨드라인상의 입력의 경우에는 해당 줄 앞에 $를 붙이도록 하겠습니다.

$chmod 755 first.sh
$./first.sh

그럼 Hello World라고 출력 결과가 나오게 됩니다.

4장 Variables (1) 요약

다른 프로그래밍 언어처럼 Bourne shell도 변수를 사용할 수 있습니다. 다만 변수 할당 시 사용되는 “=” 양옆에 스페이스가 없어야 한다는 점을 숙지해야 합니다. 예로 들어 VAR=value 는 문제가 없지만 VAR = value는 틀린 문법이라서 제대로 작동하지 않습니다. 첫번째 케이스에서는 쉘이 =를 보고 변수 할당의 명령어라고 판단을 하지만, 두번째 케이스에서는 VAR 자체를 하나의 명령어일 것이라고 판단을 한 뒤 실행하려고 할 것입니다. 그리고 = 와 value를 각각 첫번째 패러매터와 두번째 패러매터라고 판단을 할 것입니다. var.sh란 파일을 만들어서 내용을 아래와 같이 한 뒤 실행해봅시다.

#!/bin/sh
MY_MESSAGE="Hello World"
Echo $MY_MESSAGE

문자열 Hello World를 MY_MESSAGE란 변수에 할당한 뒤, echo를 사용해서 변수의 내용물을 꺼내고 있습니다. 문자열 Hello World를 쌍따옴표로 감싸고 있다는 것에 주목합니다. 변수는 하나의 값밖에 할당할 수 없습니다. 그러므로 띄어쓰기가 포함된 문자열은 쌍다옴표를 통해 감싸줘야지만 shell이 혼동하지 않습니다. 만약 쌍따옴표가 없으면, shell은 MY_MESSAGE=Hello란 명령어를 실행하고, 그 패러매터로 World를 사용한다는 식으로 해석을 하려 할 것입니다. Shell은 변수의 타입은 신경쓰지 않습니다. 내용물은 문자열일수도, 정수형일수도 있습니다. 사실대로 말하면 이것들은 모두 문자열 형태로 저장됩니다. 하지만 막상 아래와 같은 코드를 실행하면 에러가 발생합니다.

x="hello"
Expr $x + 1

즉 문자열에 1을 더하는 식인데, 해당 코드를 실행하면 expr: non-numeric argument 에러가 출력됩니다. 이는 expr이 오직 숫자만 다루는 명령어이기 떄문입니다. 그래서 적절한 Escape 처리가 필요하며 이는 6장에서 살펴볼 것입니다. 그리고 read 명령어를 사용해서 유저의 입력 내용을 변수에 담는 것도 가능합니다. var2.sh 파일을 만들어서 아래와 같이 입력합니다.

#!/bin/sh
echo What is your name?
read MY_NAME
echo "Hello $MY_NAME - hope you're well."

해당 파일을 실행하면, 유저의 입력을 받을 수 있도록 커서가 깜빡입니다. 아무거나 입력을 하면 해당 내용이 MY_NAME 변수에 입력이 됩니다. 그리고 바로 다음 줄에서 그 변수 내용물이 echo를 통해 출력됩니다. 여기서 숙지해야할 점은 read 명령어가 자동적으로 쌍따옴표를 유저인풋 내용의 양옆에 넣어준다는 것입니다. 즉 유저 입력에 스페이스가 있어도 문제없이 처리됩니다.

변수의 범위(Scope)

Bourne shell에서 변수는 미리 선언되어 있어야 할 필요가 없습니다. 하지만 만약에 선언되지 않은 변수를 읽을려고 한다면 그 결과는 공란(빈 문자열)일 것입니다. 딱히 warning이나 error는 출력되지 않습니다. 이것은 일종의 버그를 초래할 수도 있는데, 예로 들어 당신이 다음과 같이 변수에 값을 할당한다고 쳐봅시다.

MY_OBFUSCATED_VARIABLE=Hello

그리고 그 다음에,

Echo $MY_OSFUCATED_VARIABLE

을 씁니다. 실행을 하면 아무 것도 출력되지 않습니다. 일단 두 변수가 스펠링이 같지 않기 떄문입니다. 이번에는 변수의 범위에 대해서 알아보는 차원에서 export란 명령어에 대해서 알아볼 것입니다. 이 명령어가 어떤 작동을 하는지 알려면 아래 예시를 살펴봅시다. 이제 내용물을 다음과 같이 하여 myvar2.sh라는 파일을 하나 만들어봅시다.

#!/bin/sh
echo "MYVAR is: $MYVAR"
MYVAR="hi there"
Echo "MYVAR is $MYVAR"

스크립트를 실행하면 결과는 다음과 같습니다.

$ ./myvar2.sh
MYVAR is:
MYVAR is: hi there

처음엔 변수에 어떤 것도 할당되어 있지 않기 떄문에 아무 것도 출력되지 않지만, 이후 hi there라는 문자열이 할당되므로 두번째 줄에선 문제없이 hi there가 출력됩니다. 그럼 다음과 같이 실행해봅시다.

$MYVAR=hello
$./myvar2.sh
MYVAR is:
MYVAR is: hi there

커맨드라인을 통해 MYVAR 변수에 hello란 내용을 할당했음에도 불구하고 스크립트 실행 시 아무런 변화가 없습니다. 실은 여러분이 interactive shell로부터 myvar2.sh를 실행할 때 , 새로운 쉘이 생성되어 이 스크립트를 실행하게 되는 것입니다. 이는 부분적으로 첫줄에 #!/bin/sh를 넣었기 때문이기도 하죠. 그리고 여기서 바로 export 명령어를 사용할 필요가 생깁니다. export 명령어를 통해서 다른 프로그램(쉘 스크립트 등)으로부터 변수를 상속받습니다. (interactive shell에 대한 내용은 http://www.tldp.org/LDP/abs/html/intandnonint.html 참고하심 도움됩니다. 이 부분에서 저자는 쉘 레벨에 대한 설명, 즉 쉘이 재귀적으로 실행될 수 있다는 부분을 설명을 생략해서 읽는이로 하여금 좀 어렵다는 인상을 줄 수 있을 것 같습니다. 한국어로 셸 변수에 대한 정보를 조금 더 찾아보신다면 이 부분의 이해가 수월하리라 싶습니다. - 역자)

$export MYVAR
$./myvar2.sh
MYVAR is: hello
MYVAR is: hi there

만약 일단 쉘 스크립트를 나간다면, (Ctrl+d등을 통해서 - 역자) 해당 export는 파기됩니다. 예로 들어 지금 shell의 레벨이 4였는데, Ctrl+d를 통해 3으로 빠져나가는 순간, export했던 내용도 다 사라지는 것이죠. 만약 스크립트로부터 변수를 가져오고 싶다면 source 명령어를 사용하면 됩니다. source명령어는 단순하게 “.”(도트) 만으로 실행 가능합니다.

$ MYVAR=hello
$ echo $MYVAR
hello
$ . ./myvar2.sh
MYVAR is: hello
MYVAR is: hi there
$ echo $MYVAR
hi there

Hello가 담겨있던 MYVAR 변수의 내용물이 hi there로 바뀌었습니다. source(도트) 명령어를 통해서 myvar2.sh에 선언된 변수를 가져와서 덮어씌웠기 때문이죠. .profile 또는 .bash_profile이 작동하는 방식이기도 합니다.

본 게시글은 2017.04.29 마지막 수정되었습니다