들어가며
- <p>쉘 스크립트란 쉘에서 사용할 수 있는 명령어들의 조합을 모아서 만든 배치(batch) 파일이다. 리눅스에서는 여러 명령어들을 파이프(pipe), 리다이렉션(redirection), 필터(filter) 등으로 연결하여 원하는 결과를 얻어 낼 수 있다. 이런 방식으로 묶여진 명령어 조합이 반복적으로 사용된다면 이를 쉘 스크립트로, 즉 단일 명령으로 만들어 쉽게 사용할 수 있다.</p><p>스크립트라고 하는 것은 인터프리터(interpreter)에 의해 해석/실행되는 프로그램을 말한다. 어떤 종류의 인터프리터를 사용하는 가에 따라서 어떤 스크립트인가에 대한 이름이 정해진다. 쉘 스크립트, 펄(Perl) 스크립트, Tcl/Tk 스크립트 등의 이름에서 사용하는 인터프리터를 알 수 있다. 쉘 스크립트는 인터프리터로 쉘을 사용하는 스크립트를 가르킨다. 또한 어떠한 쉘을 사용하는 가에 따라서 본(bourne) 쉘 스크립트, C 쉘 스크립트, 콘(Korn) 쉘 스크립트, TC 쉘 스크립트 등으로 나뉜다.</p><p>이 연재에서는 쉘 스크립트 중의 기본이 되는 본 쉘 스크립트에 대해서 살펴볼 것이다. 본 쉘 스크립트에서 사용하는 기능과 문법은 다른 쉘에서도 지원이 된다. 따라서 실제 사용할 때는 다른 쉘을 사용할 수도 있을 것이다. 필자는 bash 1.14.7을 사용하여 설명을 할 것이다.</p><p> </p>
어떤 것이 쉘 스크립트?
- <p>우리는 알게 모르게 많은 쉘 스크립트을 사용한다. 그렇다면 어떤 것이 쉘스크립트인가? 확인을 해보는 방법은 file와 grep명령을 사용해서 찾아보는 것이다. 필자의 시스템에서의 결과는 다음과 같다.</p><p> </p>
false : Bourne shell script text igawk : Bourne shell script text remadmin : Bourne shell script text true : Bourne shell script text $ (cd /usr/bin ; file * |grep “shell script”) anytopnm : Bourne shell script text apropos : Bourne shell script text audiocompose : C shell script text audiosend : C shell script text autoconf : Bourne shell script text autoheader : Bourne shell script text autoreconf : Bourne shell script text autoupdate : Bourne shell script text bash2bug : Bourne shell script text bashbug : Bourne shell script text batch : Bourne shell script text bdftops : Bourne shell script text bzless : Bourne shell script text ...... whatis : Bourne shell script text wv-incconfig : Bourne shell script text wv-libconfig : Bourne shell script text xbm2ikon : Bourne shell script text xbmcut48 : Bourne shell script text xbmsize48 : Bourne shell script text zcmp : Bourne shell script text zdiff : Bourne shell script text zforce : Bourne shell script text zgrep : Bourne shell script text zipgrep : Bourne shell script text zless : Bourne shell script text zmore : Bourne shell script text znew : Bourne shell script text</p> |
쉘 스크립트 작성하기
- <p>스크립트의 특징 중의 하나는 그 내용이 텍스트 형식이기 때문에 일반 편집기로 볼 수 있다는 것이다. 위에서 찾는 스크립트 중 아무 것이나 cat, vi, emacs 등으로 보아라. 여러 명령들과 스크립트 문법의 조합으로 되어 있는 것을 확인할 수 있다.</p><p>스크립트의 가장 첫줄은 항상 #!로 시작한다. #! 다음에는 이 스크립트를 실행할 인터프리터와 그 실행 옵션을 지정한다. 쉘 스크립트에서는 #!/bin/sh, #!/bin/csh, #!/bin/bash, #!/bin/ksh, #!/bin/tcsh와 같이 쉘의 절대 경로를 써준다. 전통적인 관습에 의하여 #!만 써줄 경우에는 #!/bin/sh로 인식을 한다.
따라서 본 쉘 스크립트 작성시에는 첫 줄은 #!/bin/sh나 #!로 하면 된다.</p><p>이제 앞의 예제를 바탕으로 간단한 ‘findscript’ 쉘 스크립트를 작성하여 보자. 이 스크립트는 /bin, /usr/bin에서 쉘 스크립트를 찾아 보여준다.</p><p> </p>
#!/bin/sh# # findscript: /bin, /usr/bin에 있는 쉘 스크립트를 찾는다. #</p><p>(cd /bin; file * | grep “shell script”) (cd /usr/bin; file * | grep “shell script”) $ chmod +x findscript.sh $ ./findscript.sh</p> |
- <p>cat 또는 다른 편집기를 이용하여 위에서 처럼 작성을 하고, 실행 가능하도록 퍼미션을 준다. 그리고서 다른 프로그램 처럼 실행을 하면 된다. 위에서 본 것과 같이 기본적으로 쉘 스크립트는 쉘에서 사용할 수 있는 명령들의 집합이다. 여기에 덧붙여 쉘에서는 쉘 스크립트에서 사용할 수 있는 나름의 문법을 제공한다.</p><p> </p>
종료 상태 (Exit status)
- <p>각 명령들은 실행을 올바로 마치고 정상적인 종료(성공/참)하거나, 실행 오류 또는 인터럽트에 의한 중단과 같은 이유로 비정상적으로 종료(실패/거짓)할 수 있다. 이 성공과 실패는 명령의 종료 상태값으로 알 수 있다. 보통 0은 성공을 나타내며, 0이 아닌 값은 실패를 나타낸다. 쉘에서는 이전에 실행한 명령이 성공을 하였는지 실패를 하였는지를 ? 변수값에 저장을 한다.</p><p> </p>
$ echo $? 1 $ who | grep hermes44 hermes44 : 0 Sep 16 11:34 hermes44 pts/0 Sep 16 11:36 hermes44 pts/1 Sep 16 14:07 $ echo $? 0 $ false; echo $? 1 $ true; echo $? 0</p> |
#!/bin/sh # #return_exit: <인자>의 값을 종료 상태로 #반환한다. #</p><p>if [ $# -eq 0 ] then exit else exit $1 fi $ ./return_exit; echo $? 0 $ ./return_exit 8; echo $? 8</p> |
- <p>if 구문은 조건식에 따라서 분기를 한다.
형식은 다음과 같다.</p><p>if 조건식
then
명령들
[ elif 조건식
then
명령들 ]
[ else
명령들 ]
fi</p>
</p>
- <p>trap ‘명령들’ [시그널 번호들]</p>
Ctrl+\(SINQUIT,3)를 누르면 스크립트는 종료를 하게된다.</p><p> </p>
$ kill -1 | |||
1) SIGHUP | 2) SIGINT | 3) SIGQUIT | 4) SIGILL |
5) SIGTRAP | 6) SIGIOT | 7) SIGBUS | 8) SIGFPE |
9) SIGKILL | 10) SIGUSR1 | 11) SIGSEGV | 12) SIGUSR2 |
13) SIGPIPE | 14) SIGALRM | 15) SIGTERM | 16) SIGCHLD |
17) SIGCONT | 18) SIGSTOP | 19) SIGTSTP | 20) SIGTTIN |
21) SIGTTOU | 22) SIGURG | 23) SIGXCPU | 24) SIGXFSZ |
25) SIGVTALRM | 26) SIGPROF | 27) SIGWINCH | 28) SIGIO |
29) SIGPWR |
|
|
|
$ cat trap_exit trap ‘echo basename $0: signal catch’ 1 2 15 while : |
명령행 인자 (Command-line argument)
- <p>쉘 스크립트에서는 최대 9개의 명령행 인자를 받을 수 있다. 그 값은 $1~$9에 저장된다. (최신 쉘에서는 그 이상의 인자를 받을 수도 있다. ${10}과 같은 형식이다.) $0에는 실행한 쉘 스크립트의 경로가 저장된다. 또한 위에서 잠깐 보았듯이 $#에는 인자의 개수가 저장이 된다.</p><p>스크립트 중에 shift를 사용하였음을 주목하라. shift는 $1 인자를 없애고 각 인자번호를 1씩 줄인다. 즉 $2는 $1, $3은 $2, $4은 $3과 같은 식으로 된다.</p><p> </p>
# # prarg: 세 개의 인자를 출력하다. #</p><p>prog= basename $0</p><p>if [$# -eq 3 ] then echo “Script $prog path: $0” echo “Arg1: $1” echo “Arg2: $2” shift echo “Arg3: $2” else echo “Usage: $ $prog arg1 arg2 arg3” exit fi $ ./prog es 34 Usage: $ prarg arg1 arg2 arg3 $ ./prog 28 ksl 9 Script prarg path: ./prarg Arg1: 28 Arg2: ksl Arg3: 9</p> |
루프 (Loop)
- <p>쉘 스크립트에서 사용할 수 있는 루프는 세 가지가 있다.
</p>
- <p>while 조건식
do
명령들
done</p>
#!/bin/sh # # arg-while: 모든 인자를 출력한다. #</p><p>echo Argument number: $# while [ $# -gt 0 ] do echo $1 shift done $ ./arg-whilel 1 2 3 4 Argument number: 4 1 2 3 4</p> |
- <p>until 조건식
do
명령들
done</p>
#!/bin/sh # # arg-until: 모든 인자를 출력한다. #</p><p>echo Argument number: $# until [ $# -eq 0 ] do echo $1 shift done $ ./arg-until 1 2 3 4 Argument number: 4 1 2 3 4</p> |
- <p>for 변수 in [문자열 목록]
do
명령들
done</p>
# !/bin/sh # # arg-for: @ 인자앞의 인자를 출력한다. # echo Argument number: $# for arg do if [ $arg = @ ] then break fi echo $arg done $ ./arg-for 1 2 @ 3 2 4 6 Argument number: 7 1 2</p> |
case의 형식은 다음과 같다.</p>
- <p>case 변수 in
패턴1) 명령들 ;;
패턴2) 명령들 ;;
*) 명령들 ;;
esac</p>
#!/bin/sh # # check_flag: 인자를 검사하여 flag를 켠다. #</p><p>aflag=0 bflag=0</p><p>for arg do case $arg in -a) aflag=1 ;; -b) bflag=1 ;; *) echo “Usage: `basename $0` [-a] [-b]” 1>&2 exit 1 ;; esac done</p><p>echo aflag=$aflag bflag=$bflag $ ./check-flag aflag=0 bflag=0 $ ./check-flag -a aflag=1 bflag=0 $ ./check-flag -a -b aflag=1 bflag=1 </p> |
</p><p>test 식
[ 식 ]
:</p><p>식은 파일식, 문자열식, 수식의 세 종류로 크게 나눌 수 있다. :는 항상 참임을 나타낸다. while, until에서 무한 루프를 만들기 위해 사용된다.</p><p>파일식은 어떤 파일의 속성을 검사하는 것으로 다음과 같은 종류가 있다.</p><p>-b 파일 : 파일이 블럭 장치 파일이면 참
-c 파일 : 파일이 문자 장치 파일이면 참
-d 파일 : 파일이 디렉토리이면 참
-e 파일 : 파일이 존재하면 참
-f 파일 : 파일이 정규 파일이면 참
-L 파일 : 파일이 심볼릭 링크이면 참
-p 파일 : 파일이 네임드(named) 파이프이면 참
-S 파일 : 파일이 소켓이면 참
-r 파일 : 파일이 읽기 가능이면 참
-s 파일 : 파일의 크기가 0보다 크면 참
-w 파일 : 파일이 쓰기 가능이면 참
-x 파일 : 파일이 실행 가능이면 참
파일1 -nt 파일2 : 파일1이 파일2보다 새로운 파일이면 참
파일1 -ot 파일2 : 파일1이 파일2보다 오래된 파일이면 참
파일1 -ef 파일2 : 파일1과 파일2가 같은 파일이면 참</p><p>문자열식은 문자열에 대한 비교를 한다.</p><p>-z 문자열 : 문자열의 길이가 0이면 참
-n 문자열 : 문자일의 길이가 0이 아니면 참
문자열1 = 문자열2 : 문자열1과 문자열2가 같으면 참
문자열1 != 문자열2 : 문자열1과 문자열2가 다르면 참</p><p>수식은 숫자값을 비교한다. 양의 정수, 음의 정수, 0, 변수값이 올 수 있다.</p><p>값1 -eq 값2 : 값1 = 값2
값1 -ne 값2 : 값1 != 값2
값1 -lt 값2 : 값1 < 값2
값1 -le 값2 : 값1 <= 값2
값1 -gt 값2 : 값1 > 값2
값1 -ge 값2 : 값1 >= 값2</p><p>이외에도 다음과 같이 식 전체에 대한 연산이 가능하다.</p><p>! 식 : 식에 대한 부정(not)
식1 -a 식2 : 식1과 식2에 대한 논리곱(and)
식1 -o 식2 : 식1과 식2에 대한 논리합(or)</p>
'Programming' 카테고리의 다른 글
Linux C - 파일 입출력 예제 (0) | 2016.09.02 |
---|---|
Shell Script - 숫자연산 (0) | 2016.09.02 |
Linux C - gcc 옵션 (0) | 2016.09.02 |
Linux C - gcc message list (0) | 2016.09.02 |
JAVA - 객체 배열 선언 (0) | 2016.09.01 |