초보자를 위한 Shell Programming

저자 : 숭실대 머드넷

편집 : 김주석(calflove@chollian.net)

1. 쉘.

(1) Standard Input & Standard Output

간단히 설명해서 키보드에서 들어오는 명령을 표준입력이라고 하고 사용자의  터미널로 보내지는 출력을 표준출력이라고 합니다. 그 출력은 프린터, 파일로도 갈 수가 있습니다. 여기서 사용자의 터미널이라는 것은 저희가 처음에 who라는 명령어를 배울 때 tty0, tty1.... 이라고 Display됐던 것을 의미합니다. 리눅스에서는 프린터, 디스크 드라이브, 터미널 같은 것을  파일로 간주하기 때문에 각각마다 고유의  파일이름을 가지고 있습니다. 여러분들 리눅스 디렉토리 내에 보시면 /dev 라는 디렉토리가 있을 겁니다. 바로 그 디렉토리 내에 디바이스 파일들이 존재하고 있습니다. who라는 명령어로 확인했을 때 tty0라고 표시됐다면 그 터미널의 패스 이름은 /dev/tty0 일 겁니다. 터미널과 Command사이에 존재하는 것이 바로 쉘입니다. Command에서 터미널로 향하는 것이 표준출력이고 터미널에서 Command로 향하는 것이 표준입력입니다.

표준입력과 표준출력을  잘 보여주는 예가 cat이라는  명령어입니다. cat이라는 명령어 다음에  아규먼트가 붙으면 그 파일의 내용을 화면에 디스플레이 해준다는 것은 아마 아실 것입니다. 그럼 아규먼트를 붙이지 말고 cat이라는 명령어를 실행하여 봅시다.

ClassData:/# cat [ENTER]

Good morning

Good morning

Goodbye

Goodbye

^d

ClassData:/#

아래에 커서가 깜박이죠 아무 문장이나 입력하시고 [ENTER]를 치시면 그 문장이 그대로 출력됨을 볼 수가 있습니다. 사용자가 키보드로 입력한 표준입력이 그것의 표준출력에  복사가 되어 화면에 디스플레이 되는 것을 의미합니다. 한번에 한 라인만 가능합니다. 위에서 살펴본 표준입력, 표준출력  이외에 표준에러라는 것이 하나 더 있습니다. 다음 파트를  보시면 표준에러를 쉽게 이해하실 수 있을 겁니다.

(2) Redirection

방향 전환이라는 것은 표준입력이나 출력의 방향을 꼭 키보드 또는 터미널로 하는 것이 아니라  임의로 방향을 바꿔 파일에서 입력을 받거나 파일로 출력을 하는 것을 말합니다. 유닉스에서 흔히 말하는  쉘에는 본쉘과 c쉘이 있습니다. 11장에서 자세히  쉘 프로그래밍에 대해 공부할 것이므로 그냥 지금은 있다고만 하겠습니다. 방향 전환하는 기호가 본쉘이냐 c쉘이냐에 따라 약간은 다릅니다.  자 그럼 먼저  표준출력의 방향전환부터 알아보겠습니다. 이 앞에서  cat > test라는 명령어를 사용한 적  있었죠? 임의의 텍스트 파일 만드는 방법으로요 ' > '가 표준출력 방향전환기호 입니다. 아까 cat이라는 명령어 다음에 아규먼트가 붙지 않으면 표준입력이 표준출력으로 복사된다고 했죠 '>'기호와 'test' 라는 파일이름으로 인해 표준출력이 터미널로 가야되는 것이 test라는 파일로 가게되는 겁니다. 기호 방향 혼동하시면 안됩니다. 예를 들어

ClassData:/# ls > test [ENTER]

ClassData:/#

'ls'라는 명령어를 수행하면  현 디렉토리내의 파일과 서브디렉토리가  출력이 되어야 정상인데 출력이 되지  않고 있습니다. 출력될 것이 전부 test라는 파일에 들어갔기 때문입니다. 별로 어렵지 않죠? 그런데 이것도 조심해서 사용해야 됩니다. 파일이 기존에 존재하고 있다면 그 파일은 지워져 버리게 되죠.

자 이번에는 표준입력에 관한 것입니다. 역시 cat으로 예를 들어 설명해 보겠습니다.

ClassData:/# cat < test [ENTER]

Good morning

Good bye

ClassData:/#

위 명령어 test라는 파일을  표준입력으로 받아 표준출력인 터미널로 보내는 것입니다.  곧 'cat test'와 다를 게 없죠? 기호방향을 잘 기억하시기 바랍니다. 가끔 오락가락할 때가 있을 겁니다. 그리고 마지막으로 표준에러의  방향전환입니다. 표준에러의 방향전환은 본쉘을 기준으로 간략하게 설명하겠습니다. 실행하려고 하는 명령어가 시스템에 없으면 Command not found라는 메세지가 나옵니다.  그러한 메세지는 표준출력을 방향전환을 하더라도(파일로) 화면에 메세지가 나옵니다. 이러한 메세지를 표준에러라  하는데 이것의 방향을 전환해서 파일로 저장할 수 가 있습니다.

ClassData:/# ttt 2> good

ClassData:/# cat good

bash : ttt : Command not found

아래는 본쉘과 c쉘에서의 입력과 출력방향전환 기호입니다.

기호	C쉘	본 쉘
>	표준출력을 새로운 파일로	표준출력을 파일로
>!	표준출력을 기존의 파일로	사용하지 않음
>>	표준출력을 기존의 파일에 덧붙임	표준출력을 기존의 파일에 덧붙이거나 새로운 파일로
<	표준입력을 파일에서	표준입력을 파일에서
>&	표준출력,에러를 새로운 파일로	사용하지 않음
>&!	표준출력, 에러를 기존의 파일로	사용하지 않음
>>&	표준출력고, 에러를 기존의 파일에 덧붙임	사용하지 않음
1>	사용하지 않음	표준출력을 파일로
2>	사용하지 않음	표준에러를 파일로
>&2	사용하지 않음	표준출력, 표준에러를 결합하고 결과를 표준출력으로

* 참고 : 리눅스에서 본쉘은 bash, c쉘은 tcsh

(3) 파이프

우리는 앞에서 출력, 입력  방향전환에 대하여 공부하였습니다. 이번에는 파이프라는 것을 공부할 것인데 파이프라는 것은 예를 들어 어떤 명령어의 출력을  파일로 전환하고(앞에서 공부한 것임) 그 파일을 다른 새로운 명령어의 입력으로 갔다 쓸 수 있도록 하는데 사용합니다. 방향전환과는 다르게 새로운 파일을 생성하지는 않습니다. 예를 들어 설명하면 'ls'에 의한 출력의 결과를 sort -r이란 명령어행의 입력으로 넣고자 할 때에는

ClassData:/# ls | sort -r [ENTER]

위에서 파이프를 정의했듯이  어떤 명령어의 결과를 새로운 명령어의 입력으로 사용하고자 할 때  파이프를 사용합니다. '|'로 분리된 명령어의 행을 파이프라인이라고  합니다. 파이프를 사용할 때 자주 사용하는 명령어로 'tee'라는 것이 있습니다. 이 명령어는 입력하나에  두개의 출력을 낼 수가 있습니다. 이 출력은 파일, 프린터,  터미널 아무거나 상관없습니다.

ClassData:/# ls | tee test | sort -r [ENTER]

화면에 역순으로 정렬된 test의 내용과 test라는 파일이 만들어졌음을 쉽게 알 수가 있습니다. 이 명령어는 어떤 결과를 파일로 저장하고 프린터로 출력할 때 가장 많이 쓰이는 명령어입니다.

(4) 백그라운드

어떤 작업을 하다보면 그 작업량이 처리시간이 길어서  오랜 시간 동안 기다려야 하는 경우가 생깁니다. 이럴 때 이 작업이 끝날 때까지 가다릴 필요 없이 다른 작업을 할 수 있도록 해주는 것이 백그라운드입니다. 그렇게 오래 걸리는 작업은 아니지만 CD와  함께 리눅스가 구동될 때 find라는 명령어로 원하는 파일을 찾을 때 만만찮은 시간이 소비되게 됩니다. 이럴 때 그 명령어 행 제일 끝에 &를 넣어서 실행시켜 보십시요.

ClassData:/# find -name greb* & [ENTER]

[1] 118

ClassData:/#

위와 같은 명령어 행을 실행시키면 greb*을 다 찾을 때까지  기다릴 필요 없이 다른 작업을 할수가 있습니다. 보통 원하는 작업을 백그라운드로 할 때는 방향전환을 사용합니다. 왜냐하면 백그라운드로 실행시킨 명령어가 다 완료됐으면 현재 사용자가 무슨 작업을 하고 있든지 화면에 그 결과를 출력하기 때문입니다. 위의 '[1] 118'에서 '[1]'는 작업번호이고 '118'은 PID입니다. 백그라운드 작업을 죽이는 명령어로는 kill이라는 명령어를 사용하는데 두 가지 방법으로 중단시킬 수 있습니다.

첫 번째는 작업번호로 중단시키는 방법이 있고 두 번째는 PID를 이용해 중단시키는 방법이 있습니다. 우선 지금 백그라운드로 명령이 잘 실행되고 있는지 알아봅시다. 이때 사용하는 명령어로  'jobs'라는 명령어를 사용합니다.

ClassData:/# jobs [ENTER]

[1]+ Running   find -name greb* > test &

ClassData:/#

작업번호만 나오고 PID는 나노지 않죠? PID를 확인하기 위한 명령어로 ps란 명령어가 있습니다. 한번 실행시켜 보십시오. 자 그럼 백그라운드 작업을 중단시켜 봅시다.

ClassData:/# kill 118 [ENTER]

ClassData:/# jobs [ENTER]

[1]+ Terminated        find -name greb* > test

ClassData:/# jobs [ENTER]

ClassData:/#

작업번호를 가지고 중단 시킬 때에는 그 번호 앞에 '%'응 써줘야만 합니다. 그러면 위와 똑같은 결과가 나옵니다.

2. 필터.

필터라는 것은 거르는 작업을 말합니다. 즉 사용자가 원하는 방식으로  조작하는 것입니다. 예를 들어 어떠한 입력에서 원하는 부분을 뽑아 다시 출력한다거나 입력을 조합해서  원하는 출력을 뽑아내는 등의 작업을 할 때 사용합니다. 입력을 조작한다고 해서 입력이 바뀌는 것은 아닙니다. 기본적인 필터들의 명령어에 대하여 알아봅시다.

(1) cat

우리가 처음에 'cat'이라는 명령어를 다룰 때 'cat'은  파일을 만들거나 또는 파일의 내용을 화면에 출력하는 데 사용한다고 하였습니다. 그런데 이 'cat'이라는  명령어로 여러 개의 파일을 하나의 파일로 만들 수가 있습니다. 예를 들어 test1이라는 파일과 test2라는 파일을 하나의 파일로 만들려면

ClassData:/# cat test1 test2 > test [ENTER]

ClassData:/#

test파일의 내용을 살펴보면 test1과 test2의 내용이 합쳐져 있음을 볼 수 가 있습니다. 물론 입력인 test1과 test2는 변함없이 존재합니다.

(2) more

more는 파일이름을 아규먼트로 받아서 그 파일의 내용을 한 화면씩 쪼개서 출력해 주는  명령어입니다. 파일의 내용이 상당히 많을 때  cat으로 확인하면 그냥 스크롤이 일어나 위  페이지의 내용을 확인할 수가 없습니다. 이때 아주 유용한 명령어입니다. more에서 사용할 수 있는 내부적인 명령어를 알아보도록  합시다. more로 긴 텍스트 파일을 불러오도록 한 다음에 화면이 나오면 'f'를 눌러보시기 바랍니다. 한 화면씩 건너뛰어 출력하게 됨을 확인할 수 있을  겁니다. ':f'를 누르시면 현재 파일의 이름과 마지막 행의 번호가 나옵니다. 그밖에 다른 명령어들을 알고 싶으면 'h'를 눌러 보십시요. 쉘로 나가는 명령어는 'q'입니다. 이번에는 more와 같이 사용되는 옵션을 알아봅시다. 몇가지 옵션들이 있지만 가장 많이  쓰이는 옵션을 배워보도록 하겠습니다.

ClassData:/# more +100 <filename> [ENTER]

100라인이 화면의 처음에 위치하도록 출력해주는 명령어 행입니다.

(3) head & tail

'head'라는 명령어는 원하는 파일의 내용을 읽어서 처음부터 원하는 라인 수만큼 출력해 주는 명령어입니다. 원하는 라인수를 옵션으로 주지 않으면 디폴트로 10라인까지 출력합니다. 'tail'은 그 반대로 마지막에서 원하는 라인까지 출력을 해줍니다.

ClassData:/# head -15 test [ENTER]

처음부터 15행까지 test의 내용을 출력합니다.

ClassData:/# tail -15 test [ENTER]

test의 내용의 끝에 15행까지만 출력합니다. 여기서 15행이란  절대라인수가 아니라 파일의 끝에서의 상대 라인 수입니다.

ClassData:/# tail +15 test [ENTER]

test의 15행부터 끝까지 그 내용을 출력합니다.

(4) uniq

'uniq'라는 명령어는 'cat'처럼 파일의 내용을 보는 명령어 중에 하나입니다. 다른 점이 있다면 파일의 내용 중 중복되는 부분이 있으면 하나만 출력하게 한다는 것입니다.

ClassData:/# cat test [ENTER]

Good morning

Good morning

Good bye

Good bye

ClassData:/# uniq test [ENTER]

Good morning

Good bye

ClassData:/#

이 명령어의 단점은 같은 내용이 바로 인접되어 있어야만 사용 가능하다는 겁니다.

ClassData:/# cat test [ENTER]

Good morning

Good bye

Good morning

Good bye

ClassData:/# uniq test [ENTER]

Good morning

Good bye

Good morning

Good bye

ClassData:/#

uniq라는 명령어를 사용했어도 출력은 변화가 없죠? 어떻게 하면 될까요? sort라는 명령어와 같이 쓰면 되겠네요. sort라는 명령어는 알파벳순으로 정렬하는 명령어이므로 같은 내용은  바로 인접하게 되겠죠.

ClassData:/# sort test | uniq [ENTER]

Good morning

Good bye

ClassData:/#

(5) split

말 그대로 파일을 쪼개는 명령어입니다. 파일을 쪼개므로 쪼개진 갯수만큼의 파일을 생성합니다.  생성된 파일이름은 xaa, xab, xac...... 파일이 생성됩니다. 만약에 생성될 파일이름을 아규먼트로 주면 <filename>aa, <filename>ab.........로 파일이 생성됩니다. 쪼갤 라인의 갯수는 옵션으로 주면 됩니다.

ClassData:/# cat test [ENTER]

Good morning

Good bye

Good morning

Good bye

ClassData:/# split -2 test test1 [ENTER]

ClassData:/#

ls로 확인해 보면 test1aa, test1ab가 존재함을  확인할 수 있습니다. 각각의 파일은 2라인씩 쪼개진 내용을 가지고 있습니다.

ClassData:/# cat test1aa [ENTER]

Good morning

Good bye

ClassData:/#

(6) tr

tr이라는 명령어는 임의의 문자를 원하는 문자로 바꾸는 명령어입니다.

ClassData:/# cat test [ENTER]

Good morning

Good bye

ClassData:/# cat test | tr G g [ENTER]

good morning

good bye

ClassData:/#

한번에 여러문자를 바꿀수도 있습니다. 예를들어 G를 g로 또 g를 G로 바꾼다면

ClassData:/# cat test | tr Gg gG [ENTER]

good morninG

good bye

ClassData:/#

위에서 첫 번째 아규먼트의 G가 두 번째 아규먼트의 g로, 첫 번째 아규먼트 g가 두 번째 아규먼트의 G로 바뀌는 겁니다. 글자가 같아서 혼동하시면 안됩니다.

3. 본쉘 프로그래밍

(1) 쉘 프로그래밍이란?

여러분들 가운데 도스를  사용하시면서 한번이라도 autoexec.bat이라는 파일을 보시지 못한 분은 안 계실겁니다. 쉘 프로그래밍은 그것과 다를 게 전혀 없습니다. 여러분들 배치파일을 왜 사용하십니까? 한꺼번에 같이 자주 사용되는  명령어들을 하나의 명령어로 묶어서 사용하면 편하니까 그런 것 아니겠습니까?  한번이라도 배치파일 프로그래밍을 공부하신 적이 있다면 이 쉘 프로그래밍 이해하시기는 아주 쉬울 것입니다. 그렇지 않은 분들도 절대로 어렵지 않습니다.

명령어를 해석하는 쉘은 쉘  스크립트라는 것을 제공해 수준 높은 프로그래밍을 할 수 있도록 사용자에게  도움을 줍니다. 즉 도스 배치파일과 같이 여러 명령어들을  하나로 결합할 수 있고 일반 언어에서도 갖추고 있는 루프문도 사용할 수 있게끔 합니다.

유닉스에서 일반적으로 제공하는 쉘에는 본쉘과 C쉘이 있습니다. 본쉘에서 실행가능한 것은 C쉘에서 실행 가능합니다. 그러나 C쉘에서 실행 가능한 것은 본쉘에서 실행이 가능하지 않습니다. C쉘에는 본쉘에 없는 보다 발전적인 특징들을 가지고 있습니다. 잘 쓰이지는 않지만 알아두시면 언제가 쓸모가 있겠죠?

리눅스에서도 역시  쉘을 제공합니다. 유닉스의 본쉘을 본딴 bash와 유닉스의 C쉘을  본딴 tcsh입니다. 리눅스의 bash는 유닉스의 본쉘 문법을 다 포함하고 더 나아가 C쉘의 일부 문법을 포함하고 있는 보다 발전된 형식의 본쉘입니다. 그러면 먼저 리눅스의 bash로 본쉘 프로그래밍을 공부하도록 합시다.

(2) 쉘 바꾸기

ps라는 명령어를 기억하십니까? 한번 지금 ps라고 입력하신후 [ENTER]를 쳐 보십시요. 맨위에 보시변 지금 현재 쉘이 어떤 쉘인지 나올 겁니다. 만약에 bash라면 tcsh로 가시는 방법도 있습니다.

ClassData:/# exec tcsh [ENTER]

그리고 ps를 실행시켜 보십시요. 이제는 C쉘입니다. 다시 같은 방법으로 본쉘로 돌아오십시요.

ClassData:/# exec bash [ENTER]

(3) 쉘 변수

ClassData:/# man=MUDNet [ENTER]

ClassData:/# echo $man [ENTER]

MUDNet

의미를 아시겠습니까? man이라는 변수에 MUDNet이라는 정보를 저장하여 그 정보 값을 출력하는 것입니다. 위에서 유의하실 점은 man=MUDNet을 공간 없이 붙여쓰셔야 한다는 것입니다. 위에서 만약에 echo $man이라고 하였는데 $ 표시를 빠트리면 어떤 결과가 나올까요? 한번 해 보십시요.

ClassData:/# man=MUDNet [ENTER]

ClassData:/# echo "$man" [ENTER]

MUDNet

처음 예제와는 다르게 ""로 묶여 있는데도 결과는 같게 나왔죠. 차이점이 무엇일까요?

ClassData:/# man="MUDNet and         Soon sil Univ."

ClassData:/# echo $man [ENTER]

MUDNet and Soon sil Univ.

ClassData:/# echo "$man" [ENTER]

MUDNet and Soong sil Univ.

ClassData:/#

차이점을 아시겠죠. 자 만약에 위에서 $를 인쇄하고 싶으면

ClassData:/# echo \$man [ENTER]

현재 디렉토리의 내용을 변수에 저장할 수도 있습니다.

ClassData:/# dir=test* [ENTER]

ClassData:/# echo $dir [ENTER]

test test1 test2

ClassData:/#

만약에 저장되어있는 변수에 다른 정보를 저장시키려 할 때에는 그냥 그 위에 새롭게 정의를 해주시면 됩니다. 그런데 만약에 이미 변수에 저장되어있는 값을 바꾸고 싶지 않을 때에는 readonly라는 명령어를 사용합니다.

ClassData:/# man=Hwang [ENTER]

ClassData:/# readonly man [ENTER]

ClassData:/# man=MUDNet [ENTER]

bash : man : read-only variable

ClassData:/#

(4) 입력 받기

임의의 자료를 화면 상에서 입력받는 명령어로 read를 사용합니다.

ClassData:/# read man [ENTER]

MUDNet [ENTER]

ClassData:/# echo $man [ENTER]

MUDNet

ClassData:/#

(5) 환경변수

처음에 쉘로 로긴되었을 때 여러 가지 초기화 작업이 일어납니다. 그 때 쓰이는 환경에 관련된 변수들을 환경변수라 합니다.

ClassData:/# env [ENTER]

실행시키면 여러분의 현재 환경에 대한 정보가 나옵니다.

HOME :  홈 디렉토리의 위치를 저장하고  있습니다. 여러분들이 cd라는  명령어만 입력하시고 [ENTER]를  치시면 HOME에 저장되어 있는 위치로 가게 됩니다.

PATH : 도스의 path와 같습니다.

MAIL : 전자우편의 도착여부를 알려 줍니다.

PS1 : 프롬프트를 나타냅니다.

CDPATH : cd명령어의 검색경로를 명시하고 명시된  서브디렉토리를 하나씩 차례로 찾는 디렉토리의 목록을 명령어에 제공해 줍니다.

/etc/profile을 에디터로 한번 보시고 분석해 보십시요.  잘 모르시겠다구요? 음 그러면 나머지 부분을 다 보신후 다시한번 분석해 보십시요.

(6) 기본 쉘 스크립트

이제부터는 모든 것을 파일로 저장해서 한번에 실행시켜 봅시다. 다음을 test라는 파일로 만들어 봅시나.

#!/bin/sh

date

ps

자 그러면 test라는 파일이 생겼습니다. 이것을 실행시켜 봅시다.

ClassData:/# sh test [ENTER]

처음에 date라는  명령어가 실해되고 곧이어 ps라는  명령어가 실행되죠? 맨윗줄에 써있는  #!/bin/sh는 본쉘에서만 실행시킨다는 뜻입니다. C쉘에서만 실행시키고 싶으면

#!/bin/csh

아까 배운 입력받기를 다시한번 해봅시다. 우선 아래의 내용을 에디터로 타이프 하셔서 test라고 저장을 해봅시다.

echo "Enter the Sentence"

read s1 s2 s3

echo $s1

echo $s2

echo $s3

입력이 다 됐으면 실행시켜 봅시다.

ClassData:/# sh test [ENTER]

세 개의 단어를 입력하시면 그 값이 출력됩니다. 별로 어렵지 않죠? 다음을 입력하셔서 실행시켜 봅시다.

dir=`ls`

echo "This is File list"

echo $dir

의미를 이해하시겠습니까? 이런 식으로  명령어를 자신이 원하는 문자열과 같이  사용하실 수가 있습니다. 아래는 그 예입니다. 타이프하셔서 실행시켜 보십시요.`는 숫자 1키 왼쪽에 있는 키입니다.

comm=`who`

echo "I am $who"

(7) 아규먼트 받기

아규먼트는 차례대로 1, 2, 3.... 순으로 매겨집니다. 아래를 타이프하셔서 test라고 저장을 해봅시다.

echo Argument : $1 $2 $3

실행시켜 봅시다.

ClassData:/# sh test MUDnet Soong Sil [ENTER]

Argument : MUDNet Soong Sil

ClassData:/#

위에서 test라는 파일을 만들 때 만약에 $1, $2, $3의 자리를 바꾸어서 저장해서  실행시키면 어떤 결과가 나올까요? 한번 해 보십시요. 아규먼트의 갯수를 알아내는 방법 또한 있습니다. 아래를 타이프 하셔서 test라고 저장해 봅시다.

echo "Argument number : $#"

실행시켜 봅시다.

ClassData:/# sh test MUDNet Soong Sil [ENTER]

Argument number : 3

ClassData:/#

이번에는 shift라는 명령어에 대해서 공부하도록 합시다. shift라는 명령어는 아규먼트를 왼쪽으로 쉬프트 시켜주는 명령어입니다.

echo "Argument : $1 $2 $3"

shift

echo "Argument : $1 $2 $3"

위의 문장을 test라 저장한다면

ClassData:/# sh test MUDNet Soong Sil [ENTER]

Argument : MUDNet Soong Sil

Argument : Soong Sil

ClassData:/#

(8) 조건문

여러분들 중에서 프로그램 언어를 배워보신 적이 있는 분은 조건문에 대해서  아주 잘 아실겁니다. C언어에서 포인터는 잘 몰라도 조건문하나는 누구나 확실히 아실테니까요. 지금부터 하는 내용은 그것들과 다른점이 전혀 없습니다. 그러므로 이해하시는데 크게 어려움은 없으실 겁니다.

1) if  [조건] then [수행] fi

조건을 만족하면 then 이하를 수행하라는 명령어입니다. fi라는 것은 조건문의 끝임을 알려주는 기호입니다. 예를 들어서 자신이 어떤 명령어를 쉘 프로그램으로 만들었는데 그 명령어에는 항상 옵션이 사용된다고 가정할 때

if [ $# = 0 ]

then

echo <사용방법에 대한 설명>

fi

이해가 가십니까? 아규먼트가 붙지 않으면 사용방법을 출력하는 명령어입니다. 위에서 유의할 점은 대괄호 다음에 공백이 있어야한다는 것입니다. 물론 조건의 끝도 마찬가지입니다. 즉 위의 문장을 test라고 저장한 후에

ClassData:/# sh test [ENTER]

<사용방법에 대한 출력>

만약에 위 문장 아래에 다른 명령어가 있을 때 위 조건을 만족하면 실행 안되게 하는 명령어도 있습니다. 바로 exit라는 것입니다.

if [ $# = 0 ]

then

echo <사용방법에 대한 설명>

exit 1

fi

.... 어떤 또 다른 명령어

조건을 만족하게 되면 fi아래에 있는 명령어를 실행하지 않습니다.

2) if [조건] then [수행] else [조건만족하지 않으면 수행]

조건을 만족하면 then이하를 수행하고 만족하지 않으면 else이하를 수행하는 명령어입니다. 예를 들어서 아규먼트가 MUDNet이면 OK를 그렇지 않으면 NO를 출력하는 명령어는

if [ "$1" = "MUDNet" ]

then echo OK

else echo NO

fi

위의 문장을 test라는 파일이름으로 저장하고 실행시키면

ClassData:/# sh test Soong [ENTER]

NO

ClassData:/#

3) if [조건] then [수행] elif [아니면 또다른 조건 만족 여부]

조건을 만족하면 then이하를  수행하고 만족하지 않으면 또 다른 조건여부를 따져 그에 해당하는 명령어를 수행하는 것입니다. 굳이 예를 안 들어도 어떤 식인지 짐작이 가시죠? 아래는 대략적인 형식입니다.

if [..........]

then

elif [........]

then

elif [.......]

then

else

fi

4) 조건문과 같이 자주 쓰이는 기호들

=	같음

!	부정.

-a	AND

-o	OR

아래는 숫자값들의 비교에 쓰임

-eq	같다.

-ne	같지 않다.

-gt	보다 크다.

-ge	보다 크거나 같다.

-lt	보다 작다.

-le	보다 작거나 같다.

(9) 루프문

1) for in do done

다음을 타이프 하셔서 test라 저장해놓으면

for man in MUDNet Soong Sil

do

echo $man

done

실행을 한번 해봅시다.

ClassData:/# sh test [ENTER]

MUDNet

Soong

Sil

ClassData:/#

man이라는 변수에 처음에  MUDNet이라는 값이 들어가 출력을 하게 되고  다시 루프를 돌아 그 다음  아규먼트인 Soong을 그리고 마지막 Sil까지 반복적으로 수행함을 알 수가 있습니다. 더 많은 값들을 in뒤에 넣으면 그 만큼 루프가 반복됩니다.

2) for do done

위에는 아규먼트를 프로그램내에 정의를  하였고 이번에는 밖에서 아규먼트를 가지고 루프를  실행하는것을 확인하도록 합시다.

for man

do

echo $man

done

위의 문자을 타이프하여 test라는 이름으로 저장하고 실행하면

ClassData:/# sh test MUDNet Soong Sil [ENTER]

MUDNet

Soong

Sil

ClassData:/#

처음과 같은 결과가 나옴을 쉽게 알수가 있습니다.

3) while [ <조건> ] do done

while다음의 조건이 만족하면  그 조건이 만족하지 않을때까지  do와 done사이의 명령들을 반복적으로 수행하라는 명령어입니다. 다음은 그 형식입니다.

while [ 조건 ]

do

명령어

done

4) until [ <조건> ] do done

조건이 만족할때까지 반복적으로 수행하라는 명령어입니다.  다음은 그 형식입니다.

until [ 조건 ]

do

명령어

done

다른조건문과는 달리 조건문이 만족하지 않으면 반복한다는 것에 유의하시기 바랍니다.

5) case in esac

만족되어지는 조건에  따른 명령들을 선택적으로 분포시켜  놓은것을 말합니다. C언어에서의  case문과 마찬가지로 디폴트와 브레이크에 대한 명령어(기호)가 존재합니다. 디폴트 표시는 *로하고 브레이크 표시는 ;;로 합니다.

read type

case "$type" in

A)

echo I entered A

;;

B)

echo I entered B

;;

*)

echo I entered Keyboard

;;

esac

위의 예제를 입력하시고 실행시켜 봅시다.

ClassData:/#sh test [ENTER]

A [ENTER]

I entered A

ClassData:/# sh test [ENTER]

a [ENTER]

I entered Keyboard

위 case문은 여러분들이 아주 잘쓰는 명령어 여러개를 옵션화 해서 하나의 명령어로 만들때 아주 유용합니다. 만약에 대소문자를 구별하지 않으시려면 아래와 같이 해 주시면 됩니다.

a|A)

echo ..............

;;

이상으로 간단히 본쉘 프로그래밍에 대하여 공부하였습니다. 별로 어렵지 않죠?

4. C쉘 프로그래밍

C쉘은 앞서 배운 본쉘과 상당히 유사합니다. 그러나 C쉘  프로그램은 본쉘에서 사용할 수가 없습니다. 그러한 단점을 갖고도 사용되는  이유는 그만큼 막강한 기능을 발휘하고 있기 때문입니다. 이제부터 C쉘  프로그램의 기본적인것을 공부할텐데 완전히 이해하고 응용할정도가 된다면 상당히 멋있는 프로그램을 만들수 있을 겁니다.

(1) C쉘로 변환하기

앞서도 설명을 드렸지만 본쉘에서 C쉘로 변환하는 방법은

ClassData:/# exec tcsh [ENTER]

(2) 히스토리

여러분들중에 혹시 doskey가 무엇하는건지 모르시는 분 계십니까? doskey라는것은 사용자가 입력해 사용한  모든 명령들을 스택에 저장해 놓은다음 다시 그 명령어를 사용할 때 스택에서 꺼내서(방향키 이용) 사용하는 것입니다. 리눅스에도 그것과 비슷한 개념을 가지고 있는것이 있습니다. 바로 C쉘에서의 히스토리라는 것입니다. 원래는 C쉘에만 있는 개념인데 본쉘에서도 사용이 가능합니다. 왜냐하면 리눅스에서의 본쉘인 bash는  본쉘의 발전된 형식이기 때문에 그 기능을 추가로 지니고 있습니다. 보통 히스토리의 스택크기는  20개의 명령을 저장할 만큼의 스택크기를 지니고 있습니다. 그러나 이것 또한 사용자가 임의로 정할 수가 있습니다.

ClassData:/# set history=50 [ENTER]

이제 히스토리 스택의 크기는 50이(편이상 크기를 50이라 표현 함) 되었습니다. 여러분들은 C쉘에서 별로  작업을 많이 하지 않았기 때문에 히스토리내에  별로 기억되어있는 명령어가 별로 없을겁니다. 일단은 지금 C쉘 상태에서 원하는 작업을 마음대로 충분히 한번 해보도록 해 보십시요. 다 하셨습니까? 그러면 히스토리 목록을 확인하도록 합시다.

ClassData:/# history [ENTER]

어떻습니까? 지금까지 작업한 모든  내용이 각각의 고유번호를 갖고 화면에 출력되지요? 여기서 이 고유번호는 상당히 중요합니다. 왜냐하면 이제부터는 이 번호를 이용하는 방법을 배울테니까요

자 아래는 임의로 히스토리를 만든것입니다.  히스토리가 아래와 같이 구성되어있다는 가정하에서 공부를 해보도록 합시다.

1 ls -l

2 cat test

3. cat test1

4. vi test

5 rm test

6 history

만약에 ls -l이라는 명령어행을 실행시킬 필요가 있을때 다음과 같이 번호를 이용하여 할수가 있습니다.

ClassData:/# !1 [ENTER]

같은 방법으로 vi를 이용해 test라는 파일을 작성할때도 마찬가지입니다.

ClassData:/# !4 [ENTER]

여기서 주의할점은 !과 번호를 반드시 붙여써야 된다는 것입니다. !과 번호를 이용하여 명령어행을 출력 시키는 것을 알아보았는데 이번에는 !과 문자를 가지고 명령어행을 실행시키는 방법을 알아보도록 합시다.

ClassData:/# !r [ENTER]

히스토리에서 처음에 r로 시작되는  명령어는 5번임을 쉽게 알수가 있습니다. 짐작한바와 같이  위의 !다음에나오는 문자와 히스토리를 비교하여 일치하는 명령어행을 실행시킵니다. 상대적인 위치를 이용해서 실행시키는 방법도 있습니다.   예를들어 위의 4번의 'vi test'를 상대적인 위치로 실행시킨다면 여기서 상대적인 위치라는 것은 몇번전에 그것을 실행을 했나를 의미합니다.

ClassData:/# !-3 [ENTER]

히스토리를 이용해 실행하는 다른방법으로는 ?을 이용하는 방법이 있습니다.

ClassData:/# !?ory [ENTER]

history라는 명령어가 실행됩니다. 의미를 아시겠죠. 이번에는 필터와 개념이 비슷한 방법으로 사용하는 방법에 대하여 알아보겠습니다. 즉 명령어행에 포함되어있는 일부를 추출하여 새로운 명령어행에 덧붙여 사용하는 방법입니다. 여기서 알아두어야할 부호로는 ^과 $입니다. ^는 첫번째 인수를 의미하는 것이고 $는 마지막 인수를 의미하는 것입니다. 예를 들어 히스토리목록에 다음과 같은 것이 등록이 되어있다면

15 cat test test1

cat이라는 명령어에 뒤따르는 아규먼트를 추출하여 새로운 명령어의 아규먼트로 사용할 수가 있습니다.

ClassData:/# lpr !15:^ [ENTER]

위 명령어행은 lpr test [ENTER]와 같은 의미입니다. 즉  ^ 기호로서 15번의 명령어행의 첫번째 아규먼트를 뽑아낸 것입니다. ^앞에 :가있음을 주의하시기 바랍니다. 이와 다르게 test1을 뽑기위해서는

ClassData:/# lpr !15:$ [ENTER]

를 사용하시면 됩니다. 그러면 test1의 내용이 프린터로 출력이 되겠죠.

(3) 명령어의 수정

ClassData:/# !! [ENTER]

위의 명령어를 수행시켜보십시요. 도스키와 똑같죠. 바로 전에 사용했던 명령어(행)을 실행시킵니다. 만약에 여러분들이 지금  입력하고 있는명령어행이 상당히 길다고  가정합시다. 다 타이프하고 [ENTER]를  치니까 아 글쎄 그런 명령어가 없다고 메세지가 나옵니다. 자세히 살펴보니까 cat을 cay로 잘못친겁니다. 처음부터 다시 그 긴 명령어행을 치시는 분도 있을 것이고 방향키(윗)로 그 명령어행을 다시 불러와 커서로 이동하여 고치시는 분도 있을겁니다. 여기 고치는 새로운 방법이 있습니다.

ClassData:/# !!:s/cay/cat/ [ENTER]

!!는 무슨의미인지는 이제는 다 아실겁니다. s는  치환하는 것을 의미합니다. cay라고 잘못 입력된 전체 명령어행은 cat으로 고쳐져 다시 실행될겁니다.아래는 옵션 s와 비슷한 종류의 옵션을 나열한 것입니다.

h	경로명의 마지막 요소를 제거합니다.

r	파일명의 파일명 확장을 제거합니다.

t	경로명의 마지막 요소를 제외한 모든것을 제거합니다.

&	바로전의 치환을 반복합니다.

p	변화된 이벤트를 실행하지 않고 프린트 합니다.

q	일정부분 수정되는 것을 막기위해 수정될 부분을 인용합니다.

[g]s/old/new/	기존의 것을 새로운 것으로 바꿉니다.

(4) 앨리어스

앨리어스가 무슨뜻입니까? 가명, 별명 뭐 그런 뜻이죠. 즉 기존의 명령어나 명령어행을  사용자가 독특하게 이름을 붙여 그 이름으로 또같은 명령을 수행하는 것을 의미합니다. 예를 들어 엑스 위도우 실행할때  startx나 xinit을 사용하는데 그 이름이 마음에 안들어 한번 바꾸어 보겠습니다.

ClassData:/# alias MUDNet xinit [ENTER]

이제부터는 MUDNet이라고 타이프하시고 [ENTER]를 치시면 엑스가 화면에 띄어집니다. 확인해 보십시요. 여기서 MUDNet이라고 가명을 만들었다고 xinit이라는 명령어가 없어지는 것은 아닙니다.또 다른 예를 들어볼까요. 예를들어 ls라는 명령어를  실행시키면 접근허용에 대한 값이 나오지가 않습니다. ls -l이라고 해야만 파일에 대한 접근 허용이 출력이 됩니다. 이것을 ll이라는 가명으로 만들어 봅시다.

ClassData:/# alias ll ls -l [ENTER]

이제부터 ll 이라는 명령어를 사용하십시요 ls -l과 결과가 같습니다.

ClassData:/# alias [ENTER]

아규먼트를 붙이지 않고 실행시키면 현재 alias된 명령들에 대한 정보가 나옵니다. alias를 취소시키려면 unalias라는 명령어를 사용합니다.

ClassData:/# unalias MUDNet [ENTER]

앨리어스에서 아규먼트를 교체하는 방법에 대해 알아 봅시다. 아래를 실행시켜 눈으로 확인해봅시다.

ClassData:/# alias test echo \!:$ [ENTER]

ClassData:/# test MUDNet Soong Sil [ENTER]

Sil

ClassData:/#

$는 아까와 마찬가지로 아규먼트의 끝을 의미합니다. !:도 같이 사용되고 그 앞에 \이 붙음에 주의합시다.

(5) 변수

본쉘에서의 변수선언은 변수에 그냥 값이 저장되는 형식이었는데 C쉘에서는 변수앞에 set이 붙습니다. 예를들면

ClassData:/# set man = MUDNet [ENTER]

ClassData:/# echo $man [ENTER]

MUDNet

ClassData:/#

본쉘에서는 변수와 값사이에 =을 반드시 붙여 써야만 하지만 C쉘에서는 띄어써도 상관 없습니다. 다음은 C쉘에서 제공하는 배열에 관한 것입니다.

ClassData:/# set man = (MUDNet Soong Sil) [ENTER]

ClassData:/# echo $man [ENTER]

MUDNet Soong Sil

ClassData:/# echo $man[2] [ENTER]

Soong

ClassData:/# echo $man[1-2] [ENTER]

MUDNet Soong

ClassData:/#

배열임을 표시하는 괄호안에 그 값을 넣어둡니다. 배열의 인덱스는 파스칼 언어의 형식인 1부터 붙여집니다. 외부에서 빈 배열안에 원하는 값을 넣을수도 있습니다.

ClassData:/# set man = (" " " " " ") [ENTER]

ClassData:/# echo $man[2] [ENTER]

ClassData:/# set man[2] = MUDNet [ENTER]

ClassData:/# echo $man[2] [ENTER]

MUDNet

ClassData:/#

다음은 수치변수에  관한것입니다. 수치변수를 선언하는데는  @을 사용합니다. 수치를  선언할수있는것뿐마 아니라 여러가지 수식도 선언이 가능해 기본적인 연산을 할 수가 있습니다. C와 유사한점이 가장 많은 부분이기도 합니다. 예를들면

ClassData:/# @ number = 10 [ENTER]

ClassData:/# echo $number [ENTER]

10

ClassData:/# @ number += 5 [ENTER]

ClassData:/# echo $number [ENTER]

15

ClassData:/#

위에서 +=는 C 언어에서와 같이 우변의 값과 변수의 값을 더하여 좌변에 값을 넣음을 의미합니다. 아래는 각각의 기호에 대한 기능을 정리해 놓은 것입니다.

%	나머지를 의미합니다.

/	나누기를 의미합니다.

*	곱하기를 의미합니다.

-	빼기를 의미합니다.

+	더하기를 의미합니다.

>>	오른쪽 쉬프트 연산입니다.

<<	왼쪽 쉬프트 연산입니다.

>	보다 큼을 의미합니다.

<	보다 작음을 의미합니다.

>=	보다 크거나 같음을 의미합니다.

<=	보다 작거나 같음을 의미합니다.

!=	같지않음을 나타냅니다.

==	같음을 나타냅니다.

&	AND

^	EXCLUSIVE OR

&&	AND

||	OR

++	변수의 증가를 의미합니다.

--	변수의 감소를 의미합니다.

+=	좌변과 변수의 값을 더한후 그 결과를 변수에 넣습니다.

-=	변수의 값에서 좌변을 뺀 다음 그 결과를 변수에 넣습니다.

*=	좌변과 변수의 값을 곱한후 그 결과를 변수에 넣습니다.

/=	변수의 값을 좌변으로 나누어 그 값을 변수에 넣습니다.

%=	변수의 값을 좌변으로 나누어 그 나머지를 변수에 넣습니다.

위에서 &과 &&의 차이는 &는 값을 AND 연산한다는 뜻이고 &&는 논리적인 AND를 의미합니다. 다음은 수치배열에 대한 설명입니다. 수치배열은 그냥 배열과 사용하는 방식이 똑같습니다. 역시 인덱스는 파스칼의 문법을 따르고 있습니다. 아래는 그 예입니다.

ClassData:/# set number = (0 0 0 0) [ENTER]

ClassData:/# @ number[2] = 10 [ENTER]

ClassData:/# @ number[3] = ($number[2]+10) [ENTER]

ClassData:/# echo $number [ENTER]

0 10 20 0

ClassData:/#

약간 다른점이 하나있죠. 배열에서는 외부에서 값을 넣을때 set을 사용했는데 수치배열에서는 @를 사용합니다.

(6) 환경변수

본쉐과 마찬가지로 C쉘에서도 그 환경을 결정하는 환경변수들이 있습니다.

ClassData:/# setenv [ENTER]

여러분들이 사용하고 있는 C쉘의 현재 환경을 디스플레이 합니다. 다음은 환경변수의 역할을 정리해 놓은 것입니다.

cdpath	cd 명령어의 검색경로를 나타냅니다. 사용자가 할당을 하기위해서는 앞에 set을 붙여 할당을 합니다.

history	히스토리의 스택크기를 나타냅니다. 위에서 해본겁니다.

HOME	본쉘의 홈과 같습니다. 사용자 계정후에 계정된 사용자가 로긴될 홈 디렉토리를 의미합니다.

PATH	쉘이 명령어를 찾기위한 검색 경로입니다.

prompt	C쉘 프롬프트를 나타냅니다. 예를 들어 ClassData:/#과 같은 것을 말합니다. 물론 바꿀수 있습니다.

echo	이 변수가 지정되면 이 변수는 각 명령어와 그 인수를 실행되기 전에 되돌려 보냅니다.

ignoreeof	ctrl+d 키를 이용한 쉘의 종료가 안되게 합니다. 이때 쉘 종료할 때는 logout을 해야만 합니다.

noclobber	이 변수는 사용자가 방향전환을 하고 있을때 overwriting되어지는 것을 방지합니다.

noglob	이 변수는 애매한 파일명의 확장을 막습니다. *, ?, [] 기호를 애매한 파일명으로 해석하지 않습니다.

nonomatch	파일에 대응되지 않는 애매한 파일명이 파일명의 확장없이 명령어로 사용됩니다.

notify	백그라운드 명령어가 완료되면 사용자의 터미널에 메세지를 보냅니다.

(10) 루프문

루프문은 조건을 만족하는 한 계속해서 어떠한 명령어(행)를 실행시키는 문장 구조입니다.

1) foreach

foreach명령어는 본쉘에서의 for in과 사용방법과  용도가 같습니다. 즉 어떠한 내부의 아규먼트를 순차적으로 명령어(행)의 입력으로 사용합니다. 아규먼트 끝까지 다 사용하면 루프문은 중단이 됩니다. 다음은 foreach의 형식입니다.

foreach 변수 ( 아규먼트 )

아규먼트를 인수로 같는 명령어

end

아규먼트가 여러개 오면 차례대로 사용되어 집니다. 그리고 루프문을 벗어납니다.

foreach man ( MUDNet Soong Sil )

echo $man

end

위의 예제를 test라 저장하면

ClassData:/# csh test [ENTER]

MUDNet

Soong

Sil

ClassData:/#

2) while

while문은 그 다음의 조건이 만족하는 한 계속 명령을 반복적으로 실행하는 문장 구조입니다. 다음은 그 형식입니다.

while 조건

실행문

end

다음은 while문을 사용하여 1부터 10까지 더하는 프로그램입니다.

set limit = 10

set n = 1

set sum = 0

while ($n <= $limit)

@ sum += $n

@ n++

end

echo The Sum is $sum

위의 예제를 test라 저장하고 실행을 시켜 봅시다.

ClassData:/# csh test [ENTER]

The Sum is 55

ClassData:/#

이상으로 기본적인 C쉘 프로그래밍을 마치겠습니다.