3 |
쉘 프로그램 입/출력 |
(1). 사용자 출력 지정
■ echo 명령어
echo 명령어는 뒤에 오는 내용을 화면에 출력하여 준다. 기본적으로 한 개의 echo 구문이 한 개의 라인을 차지하게 된다. echo 명령어는 모든 쉘에서 사용가능하다. echo 명령어는 뒤에 오는 모든것을 스트링으로 인식하고 표준출력(모니터)에 출력하는 역할을 가진다.
ehco 명령어 뒤에 큰 따옴표(""), 작은 따옴표('')등이 없으면, 공백(여러개의 탭이나 공백)은 하나의 공백으로 표시된다. echo 명령어 뒤에 큰 따옴표를 사용하게 되면, 큰 따옴표("") 안에서 쉘이 해석할 수 있는 것은 $(달러싸인), ``(역 따옴표), \(역 슬래쉬)등이다.
echo 명령어의 출력결과보다 더 자세하게 출력을 제어 하기 위해서는 print 명령어를 사용할 수 있다. print 명령어는 ksh 쉘이상에서 사용할 수 있다. print(1) 명령어의 자세한 사용법에 대해서는 매뉴얼을 통해 확인 하기 바란다. 이 교재에서는 print 명령어에 대한 자세한 내용은 기술하고 있지 않다.
# vi echo.sh
#!/bin/sh
echo 한줄을 띄운다. echo -n "Todays date and time: " date 명령어 수행과 같은 줄에 출력된다. date date 명령어 echo 한줄을 띄운다. |
(Key Point)
(ㄱ) echo 명령어 사용 방법(개행문자 무시하는 2가지 방법)
echo -n "~"
echo "~ \n"
# chmod 755 echo.sh
# ./echo.sh
Todays date and time: 2015. 11. 06. (금) 15:53:30 KST
|
[참고] echo 명령어에서 쓰이는 탈출 문자(Escape Charater) | |
∖a |
alter charater |
∖b |
backspace |
∖c |
print line without new-line |
∖f |
form-feed |
∖n |
new-line |
∖r |
carriage return |
[EX1] print line without new-line
echo 명령어 다음에 오는 명령어의 echo 명령어 출력 결과에 같이 붙여서 출력하고 싶은 경우가 있다. 이런 경우 기본 PATH 변수에 정의 되어진 /usr/bin/echo 명령어를 사용하게 되면, ESCAPE 문자 중에서 "\c"를 사용한다. 하지만 /usr/ucb/echo 명령어를 사용하는 경우에는 echo 명령어의 -n 옵션을 사용한다.
# cat echo.sh
#!/bin/ksh
/usr/bin/echo "TIME: \c" /* date 명령어 출력을 붙여서 출력 */ /usr/bin/date |
or
#!/bin/ksh
/usr/ucb/echo -n "TIME: " /* date 명령어 출력을 붙여서 출력 */ /usr/bin/date |
or
#!/bin/ksh
/usr/bin/echo "TIME: `date`" /* date 명령어 출력을 붙여서 출력 */ |
개행문자를 무시하는 방법이 쓰이기 때문에 알아두자
(2). 사용자 입력 읽기
■ read 명령어
파일이나 터미널로부터 입력을 읽어 오기 위해서는 내장명령어 read를 사용한다. read 명령어는 개행문자가 나타날 때까지 행을 읽어 들인다.
명령어는 사용자가 캐리지 리턴을 입력할 때까지 프로그램을 일시 중지할 목적으로도 사용할 수 있다.
read 명령어 다음은 변수에 이름이 지정될 수 있으며, 지정된 변수안에 표준 입력으로 부터 읽어 들인 내용을 저장한다.
만약 read 명령어 다음에 여러개의 변수가 지정이되면, 표준 입력으로 부터 읽어들인 내용중 첫번째 단어를 첫번째 변수에 지정하고
두번째 단어는 두번째 변수에 지정되고 나머지 단어는 마지막 변수에 저장이 된다.
read 명령어에 대한 요약은 다음과 같다.
형식 |
설명 |
read answer |
표준 입력으로부터 한행을 읽어서 변수 answer에 저장한다. |
read first last |
표준 입력으로부터 한행을 읽어서 그중 첫 단어는 변수 first에 저장하고 나모지는 last에 저장한다. |
[EX1] read 명령어를 사용한 예
스크립트 실행시 read 명령어를 통해 표준입력으로 입력을 받을수 있다.
# vi read.sh
#!/bin/ksh
echo -n "What Your Name ? : " read answer last
echo $answer <= 사용하기때문에 $를 붙히는거, 헷갈리니 꼭 이해하고 넘어가자 echo $last |
(Key Point)(ㄱ) read 명령어로 변수 선언 방법
# chmod +x read.sh
# ./read.sh
What your Name?: hong gil dong hong gil dong |
[EX2] 스크립트 중간에 화면 멈추기
스크립트 프로그램 중간에 화면을 멈추기 위해서 read 명령어가 수행 될수도 있다. read 명령어 다음에 특별한 변수가 지정이 없는 표준출력의 입력값은 REPLY 변수에 기본 저장된다.
# vi enter.sh
#!/bin/ksh
echo "Welcome To My Server" echo echo "Press Any Key .... Continue" read |
(Key Point)(ㄱ) 스크립트 실행 중간에 잠깐 멈추기
# chmod +x enter.sh
# ./enter.sh
Welcome To My Server
Press Any Key .... Continue <ENTER> <----- '<ENTER> 입력' |
출력은 echo명령어
입력은 read명령어
4 |
산술 연산 |
본쉘은 자체적으로는 산술 연산을 지원하지 않는다. 간단한 정수 연산이 필요한 경우, 일반적으로 expr 명령어를 사용한다.
부동소수점을 계산할 경우에는 awk 명령어 또는 bc 명령어을 사용한다.
산술 계산은 본 쉘에 내장되어 있지 않기 때문에 루프 등에서 사용하는 증감식도 성능에 영향을 미친다.
즉 증감이 일어날 때마다 새로운 프로세스를 생성해서 계산을 처리한다. (EX: expr(Expression))
기본적으로 숫자를 계산하려는 능력은 쉘에게 없다.
■ 정수 타입 산술 연산과 expr 명령어
----------------------------------------
# expr 1 + 4 /* 더하기 */
# expr 4 - 1 /* 빼기 */
# expr 4 ∖* 3 /* 곱하기 */ 아스타리스크가 아닌 곱하기로 편하기 위해 백스페이스를 써줘야한다.
# expr 10 / 2 /* 나누기 */
# expr 10 % 3 /* 나머지 */
----------------------------------------
# NUM=1
# NUM=`expr $NUM + 1` => 변수를 선언할땐 띄어쓰기를 쓰면안되고 백커터로 묶어주고 띄어쓰기 하는 것
# echo $NUM
2 |
[EX1] 프로세스 크기(메모리 사용 사이즈) 계산
한개의 프로세스의 메모리 크기를 사용량을 확인하는 예를 들어 보자.
ps 명령어의 -l 옵션을 사용하면 SZ 필드에 숫자는 페이지사이즈(pagesize) 단위로 만큼의 용량을 나타낸다.
페이지사이즈 단위는 스팍용은 8K 단위, 인텔용은 4K 단위로 되어 있다.
따라서 프로세스의 용량(B, KB, MB, GB, ...)을 확인하기 위해서 기본 단위를 환산해야 한다.
# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 0 22536 22533 0 50 20 ? 237 ? pts/6 0:00 ksh 0 O 0 22613 22536 0 50 20 ? 236 pts/6 0:00 ps |
# pagesize /* SPARC : 8192, INTEL(X86) : 4096 */
8192 |
# expr 237 \* 8192 (# expr 237 '*' 8192)
1941504 |
# expr 1941504 / 1024
1896 |
-> 약 1.7M 정도
-> 프로세스의 메모리(RAM + SWAP) 사용 용량 계산
[EX2] 부동소수점 계산
expr 명령어로는 자연수 계산밖에는 할 수 없다. 부동소수점 계산은 bc 명령어나 nawk 명령어를 사용하여 계산하여야 한다.
# n=`echo "scale=3 ; 13 / 2" | bc`
# echo $n
6.500 |
# product=`nawk -v x=2.45 -v y=3.123 'BEGIN { print "%.2f∖n", x*y }'`
# echo $product
7.65 |
5 |
조건문 |
조건의 표현과 흐름제어
- if 구문
- case 구문
(1). 조건의 표현과 흐름제어
조건 명령어는 조건식의 참과 거짓에 따라 작업 수행 여부를 결정한다. if는 의사 결정을 위해 사요하는 가장 간단한 형태의 명령어이다. 본쉘에서 if 다음에는 명령어가 온다. 이 명령어는 시스템 명령어일수도 내장 명령어일수도 있다. 명령어의 종료 상태가 조건식을 판단하는데 쓰인다.
조건식을 평가한기 위해 내장 명령어인 test를 사용할 수도 있다. 이 명령어는 대괄호([ ])와도 관련이 있다. test 명령어를 사용하거나 대괄호 안에 식을 넣어도 된다. test 명령어에 따라오는 식에는 쉘 메타문자(와일드카드)를 사용할 수 없다. 명령어의 결과는 0 일때 성공을 의미하고, 0 이 아닐 때는 실패를 의미한다.
■ test 명령어 ([ ])
식을 평가하고 그 식에 대한 논리값을 반환한다. 종료 상태가 0이면 참을 의미하고 0이 아니면 거짓을 의미한다. test 명령어와 [ ]는 같은 기능을 갖는다.
if [ -f /etc/profile ] ; then
. /etc/profile
fi
or
if test -f /etc/profile ; then
. /etc/profile
fi
파란색 표시된 것들 꼭 알아두자
■ (파일 테스트) 파일 관련 test 연산자 <= 대괄호 안에 들어갈 수 있는 것들
연산자 |
설명 (다음의 경우 참) |
-e file |
파일이 존재하는 경우 |
-d file |
파일이 존재하고 디렉토리인 경우 |
-f file |
파일이 정규 파일인 경우 |
-b file |
파일이 존재하고 블록 디바이스 파일인 경우 |
-c file |
파일이 존재하고 문자 디바이스 파일인 경우 |
-p file |
파일이 존재하고 파이프나 이름이 있는 파이프(FIFO 파일)인 경우 |
-S file |
파일이 존재하고 소켓인 경우 |
-L file |
파일이 존재하고 심볼릭 링크인 경우 |
-r file |
파일이 존재하고 읽을 수 있는 경우 |
-w file |
파일이 존재하고 쓰기 가능한 경우 |
-x file |
파일이 존재하고 실행할 수 있는 경우 |
-u file |
파일이 존재하고 SetUID 비트가 설정된 경우 |
-g file |
파일이 존재하고 SetGID 비트가 설정된 경우 |
-k file |
파일이 존재하고 Sticky 비트가 설정된 경우 |
-s file |
파일이 존재하고 빈 파일이 아닌 경우 |
fileA -nt fileB |
fileA가 fileB보다 더 나중에(최근에) 생성된 경우 |
fileA -ot fileB |
fileA가 fileB보다 더 이전에(나중에) 생성된 경우 |
fileA -ef fileB |
fileA과 fileB가 같은 파일을 가리키고 있는 경우 |
■ (문자열 테스트) 문자열 관련 test 연산자
연산자 |
설명 |
stringA = stringB |
stringA가 stringB와 같은 경우 |
stringA != stringB |
stringA가 stringB와 같지 않은 경우 |
stringA < stringB |
stringA가 stringB보다 사전순서로 먼저 나오는 경우 |
stringA > stringB |
stringA가 stringB보다 사전순서로 나중에 나오는 경우 |
-z string |
string의 길이가 0인경우 |
-n string |
string이 NULL이 아닌 경우 |
■ (수치 테스트) 산술연산 test 구문
연산자 |
설명 |
exprA -eq exprB |
산술연산 exprA와 exprB가 같은 경우(-eq: equal) |
exprA -ne exprB |
산술연산 exprA와 exprB가 같지 않은 경우(-n: not equal) |
exprA -lt exprB |
산술연산 exprA가 exprB보다 작은 경우(-lt: less than) |
exprA -le exprB |
산술연산 exprA가 exprB보다 작거나 같은 경우(-le: less equal) |
exprA -gt exprB |
산술연산 exprA가 exprB보다 큰 경우(-gt: great than) |
exprA -ge exprB |
산술연산 exprA가 exprB보다 크거나 같은 경우(-ge: great equal) |
exprA -a exprB |
exprA가 참이고 exprB가 참인경우 |
exprA -o exprB |
exprA가 참이거나 exprB가 참인경우 |
(주의) 숫자의 크기를 비교하는 경우 소수점 이하의 숫자는 무시된다.
■ test 구문에서 사용되는 연산자
① 논리 부정 연산자(NOT)
다른 연산자와 함께 사용되며 파일 test에 이용된다.
if [ ! -s file ] ; then
echo "file size is zero"
fi
② 괄호(Grouping)
실행 순서를 변경하기 위해 사용하며 괄호의 양쪽에는 공백이 필요하다. 그리고 의미없는 순수한 괄호의 의미를 사용하기 위해 괄호 앞에 백슬래쉬를 넣는다.
if find / ∖( -perm -4000 ∖) -o ∖( -perm -2000 ∖) -type f > /dev/null ; then
echo "SetUID or SetGID Found"
fi
③ 논리곱 연산자(AND)와 논리합 연산자(OR)
fi [ ∖( "$VAR" -ge 0 ∖) -a ∖( "$VAR" -lt 10 ∖) ] ; then
echo "$VAR is small number"
fi
if [ -n "$str" -o -r $HOME/.profile ] ; then
echo "Hello, Test."
fi
④ 연산자 우선 순위
■ 괄호(()) > 논리부정연산자(!) > 논리곱 연산자(-a) > 논리합 연산자(-o)
---------------------------------------------------------------------------------------------------------------------
조건문
■ if 구문
■ case 구문
(2). if 구문
흐름 제어 중에서 가장 단순한 형태가 바로 조건문이며 본 쉘에서 if 구문을 사용한다. 조건문은 조건을 내걸고 이 조건이 참인지 거짓인지에 따라 수행 여부를 결정한다. 조건에는 쉘 변수 값, 파일 특징, 명령의 올바른 실행 여부 등이 해당된다. 조건문에는 3가지 패턴이 존재하며 아래와 같다.
[표현식1]
명령어가 정상적으로 수행이 되면 statements을 실행한다.
if 명령어 명령어는 실행되는 것이라 $?에 들어있는 값같이 Return값이 있어서 그냥 써짐 then statements fi |
[표현식2]
“test 표현식“ 조건이 참이면 statements을 실행한다.
if test 표현식 then statements fi |
[표현식3]
“표현식” 조건이 참이면 statements을 실행한다.
if [ 표현식 ] test를 안쓴 경우 대괄호를 쓰면서 공백이 꼭 필요하다 then statements fi |
(주의) 조건 부분에 명령어가 오는 경우 test 명령어를 사용하지 않는다.
또한 구문에 관한 종류도 여러 가지가 존재한다.
[표현식1]
condition이 참이면 statements을 실행한다.
if condition then statements fi |
[표현식2]
condition이 참이면 statements을 실행한다. 그렇지 않으면 statement2을 실행한다.
if condition then statement1 else statement2 fi |
[표현식3]
condition1이 참이면 statement1을 수행하고 condition2가 참이면 statement2을 수행하고 그렇지 않으면 statement3을 실행한다.
if condition1 then statement1 elif condition2 then statement2 else statement3 fi |
or
if condition1 then statement1 elif condition2 <= if대신 elif라고 쓴다. then statement2 elif condition3 then statement3 else statement4 fi |
[예제1] "if ~ then ~ fi" 구문 실습 예
아래 예제는 특별한 파일을 읽어 들여서 파일이 존재하고 실행파일이면 실행하는 예제이다.
# vi execfile.sh
#!/bin/ksh
echo -n "Enter Your Filename : " /* 파일 이름을 입력 받는다. */ read FILENAME
if [ -x $FILENAME ] ; then /* [ ]안에 공백 꼭 필요, 조건: 파일에 실행 권한이 존재하면 */ . $FILENAME fi |
(Key Point) (ㄱ) if ; then ; fi 구문 사용
# vi /test/test.exe
cal |
# chmod 755 /test/test.exe
# chmod 755 execfile.sh
# ./execfile.sh
Write File Name: /test/test.exe
11월 2015 일 월 화 수 목 금 토 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
[참고] if 구문의 간단화 |
기존의 프로그래머들은 코딩의 길이를 길게 프로그램하는 것 보다는 간단하게 만드는 것을 더 선호하게 된다. 다음은 if 구문을 간단하게 표현한 예이다.
if [ -f /etc/profile ] then . /etc/profile fi
위와 같은 뜻으로 동작하는 구문
[ -f /etc/profile ] -a . /etc/profile (= [-f /etc/profile ] && . /etc/profile ) |
[예제2] "if ~ elif ~ else ~ fi" 구문 실습 예
아래 예제는 지정한 파일을 읽어 들여서 디렉토리인지 아닌지를 검사하는 프로그램이다.
# vi dir.sh
#!/bin/ksh
echo -n "Enter Your Filename ? : " read FILENAME
if [ -d $FILENAME ] ; then echo "File is a Directory." elif [ -f $FILENAME ] ; then echo "File is a regular file." else echo "Not Found." fi |
(Key Point)
(ㄱ) read 명령어로 입력 받기
(ㄴ) if ; then ; elif ; then ; else ; fi 구문 사용
# chmod 755 dir.sh
# ./dir.sh
Enter Your Filename ? : /etc/passwd File is a regular file. |
[예제3] if 구문을 사용한 인자(Argument) 처리 구문 예제
다음 예제는 파일이 5120bytes 보다 크면 큰 파일이라고 표시하고 5120bytes 보다 작으면 작은 파일이라고 표시하는 스크립트이다.
vi /파일.sh
if 조건
elif exit 1
elif exit 2
else exit 3
-------------
./파일.sh
echo $?
1,2,3 중 어떤 오류로 처리 된지 개발자는 알 수 있다.
# vi filesize.sh
#!/bin/ksh
if [ $# -ne 1 ] ; then /* 조건: 인자(Argument) 1개가 아니면 */ echo "Usage : $0 filename" exit 1 <= 비정상 종료를 뜻하는 1 fi
FILESIZE=`wc -c < $1` /* FILESIZE=`/usr/bin/ls -l $1 | awk '{print $5}'` */
if [ "$FILESIZE" -le 5120 ] ; then echo "This file($1) is a small file" else echo "This file($1) is a big file" fi |
# wc -c /etc/passwd | awk '{print $1}' 1939
# ls -l /etc/passwd | awk '{print $5}' 1939
(Key Point)
(ㄱ) 명령어의 인자 개수 판별 방법
(ㄴ) 파일의 크기 판별 방법
# chmod 755 filesize.sh
# ./filesize.sh /etc/passwd 반드시 인자를 하나 받아야되도록 만듬
(== $1)
The file(/etc/passwd) is a small file |
파일의 크기를 계산하여서 변수에 선언하는 작업은 여러 가지 방법이 있을 수 있다. 만약 프로그램의 크기가 엄청 큰 파일이 있는데 위와 같은 방식으로 파일의 크기를 인식하게 되면 시간상의 문제가 생길 우려가 있다. 그럴때는 다음을 참고해 보자.
예제 방식filesize=`wc -c < $1` 명령어를 사용하여 처리한다.
다른 방법find $DIR -name $FILENAME -type f -exec awk '{ print $5 }' {} ∖; 명령어를 통해 파일의 크기를 찾는 방법을 사용한다.
또 다른 방법ls -l $filename | awk '{ print $5 }' 명령어를 통해 파일의 크기를 찾는 방법을 사용한다.
[참고] 인자 변수의 개수 판별 |
■ (명령어의 인자가 한개가 아니면 에러를 출력하고 프로그램 종료) # cat args1.sh ---------------------------------------------------------------------------- #!/bin/ksh
if [ $# -ne 1 ] ; then /* -ne: not equal, 조건: 인자가 1개가 아니면 */ echo "Usage : $0 filename" exit 1 fi ..... (중략) ..... ----------------------------------------------------------------------------
■ (명령어의 인자가 없으면 에러를 출력하고 프로그램 종료) # cat args2.sh ---------------------------------------------------------------------------- #!/bin/ksh
if [ $# -eq 0 ] ; then /* -eq: equal, 조건: 인자가 없으면 안된다.*/ echo "Usage : $0 filename" exit 1 fi ..... (중략) ..... ----------------------------------------------------------------------------
|
[예제4] if 구문 사용시 조건에 명령어 사용 예
아래 예제는 특정한 파일에서 특정한 문자열이 있으면 찾았다고 표시해 주는 스크립트이다.
# vi findstring.sh
#!/bin/ksh
if [ $# -ne 2 ] ; then /* 조건: 인자가 2개가 아니면 */ echo "Usage : $0 pattern filename" exit 1 fi
if grep $1 $2 > /dev/null 2>&1 ; then /* 조건: 파일에서 특정한 패턴을 잘 찾으면 */ echo "Special pattern found" else echo "Special pattern not found" fi |
(Key Point) (ㄱ) if 구문에 test 연산자를 사용하지 않고 명령어를 사용하는 경우
# chmod 755 findstring.sh
# ./findstring.sh root /etc/passwd
Special pattern found |
(다른예)
#!/bin/ksh
if [ $# -ne 2 ] ; then echo "Usage : $0 pattern filename" exit 1 fi
grep $1 $2 > /dev/null 2>&1 if [ $? -eq 0 ] ; then echo "Special pattern found" else echo "Special pattern not found" fi |
[예제5] 변수의 NULL 값 점검 예제
NULL 값 검사를 하는 예제이다.
# cat nullcheck.sh
#!/bin/ksh
IP=172.16.8.254 if [ "X${IP}" != "X" ] ; then ping -s ${IP} fi |
(Key Point) (ㄱ) 변수가 NULL 값인지 점검
# chmod +x nullcheck.sh
# ./nullcheck.sh
널값(Null Value)을 검사하는 방식은 여러 가지가 있다.
아래 방법은 널값을 점검하는 구문이다.
[ "$VAR" = "" ]
or
[ ! "$VAR" ]
or
[ -z "$VAR" ]
or
[ "X${VAR}" != "X" ]
마지막 방법이 가장 많이 쓰이게 되는데 X을 사용하는 이유는 변수 VAR이 널인 경우에도 연산자 !=의 양쪽에 적절한 피연산자를 위치시키기 위해서이다.
# vi /etc/profile 해석
..... (중략) ..... if [ $UID -gt 99 ] && [ "`id -gn`" = "`id -un`" ]; then umask 002 else umask 022 fi for i in /etc/profile.d/*.sh ; do if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . $i else . $i >/dev/null 2>&1 fi fi done unset i unset pathmunge ..... (중략) ..... |
id -un => root, id -gn => root
즉 새로 생긴 ID는 002로 가져가고
나머지 시스템 관리자들은 022로 가져가라
# cat /etc/profile
..... (중략) ..... if [ "$TERM" = "" ] /* $TERM 변수의 NULL 값 확인 */ then if /bin/i386 /* if 구문에서 명령어 사용시 test 연산자 사용하지 않음 */ then TERM=sun-color else TERM=sun fi export TERM fi ..... (중략) ..... |
[참고] linux200(/etc/profile)
---------------------------------------------------------
if [ -z "$EUID" -a -x /usr/bin/id ]; then
EUID=`id -u`
UID=`id -ru`
fi
if [ -z "$INPUTRC" -a ! -f "$HOME/.inputrc" ]; then
INPUTRC=/etc/inputrc
fi
---------------------------------------------------------
(3). case 구문
여러 패턴을 검사하고 적절한 구문을 실행한다. case 명령어는 다중분기 명령어로 if/elif 구문 대신 사용될 수 있다.
case 구문의 변수가 pattern1, pattern2 중의 하나와 일치하면, 그 값이후부터 이중 세미콜론(;;)이 나올 때까지의 명령어들이 실행된다.
수행 후에는 esac 다음으로 프로그램의 제어가 옮겨진다.
case 변수와 대용되는 것이 없으면 *) 기호 다음에서부터 esac 사이의 문장들을 수행한다.
*)의 역할은 if/else 조건구문에서 else 문장과 동일하다. case 변수의 값에는 와일드카드나 | (OR 연산자) 를 사용할 수 있다.
[표현식]
case VAR in pattern1 | pattern2 | ....) statement ;; <= 세미콜론 2개는 break의 역할을 한다. pattern3 | pattern4 | ....) statement ;; ..... *) statement ;; esac |
[참고] case 구문을 위한 쉘 메타문자 | |
메타문자 |
설명 |
? * [] |
Any single character zero or more occurrences of any character Any single character in the specified set |
[예제1] 종합 툴 만드는 예제
쉘 프로그램을 만들다 보면, 여러개의 쉘스크립트를 모아서 선택적으로 수행하고 싶을 때가 있다. 이런 경우 case ~ in ~ esac 구문을 사용하면 보기도 좋고 구현도 쉽게 작성이 가능하다.
종합 툴의 메뉴을 만들어 보자.
# vi tools.sh
#!/bin/ksh
echo "====================================================" echo " (1). who (2). date (3). pwd " echo "===================================================="
echo -n "Enter Your Choice(1-3)? : " /* 선택할 수 있는 번호를 입력 */ read NUMBER
case $NUMBER in /* 선택된 번호에 따라 분기 */ 1) who ;; 2) date ;; 3) pwd ;; *) echo "Error... Try Again" <= Error 처리는 어떤경우든지 처리해줘야지 된다. exit 1 ;; esac |
(Key Point)
(ㄱ) case .... in ; esac 구문 사용
# chmod 755 tools.sh
# ./tools.sh
==================================================== (1). who (2). date (3). pwd ==================================================== Enter Your Choice? : 1 <---- '1' 입력 root pts/2 8월 9 13:29 (192.168.10.1) root pts/3 8월 9 13:29 (192.168.10.1:0.0) |
# ./tools.sh
==================================================== (1). who (2). date (3). pwd ==================================================== Enter Your Choice? : 2 <---- '2' 입력 2008년 8월 9일 토요일 오후 06시 34분 50초 |
[예제2] 쉘 프로그램에서 yes/no 입력 받기 예제
yes, no을 입력 받는 case문을 작성해 보자.
# vi yes.sh
#!/bin/ksh
echo "Enter Your Choice? (y/n) : \c" read ANSWER
case $ANSWER in yes | Y | Yes | YES | y) echo "Yes... Entered" ;; no | N | No | NO | n) echo "No... Entered" ;; *) echo "Answer not recongnize" exit 1 ;; esac |
(Key Point) (ㄱ) yes/no 입력 받기
# chmod 755 yes.sh
# ./yes.sh
Enter Your Choice? (yes/no) : y Yes... Entered |
(다른 예)
#!/bin/ksh
echo "Enter Your Choice? (y/n) : \c" read ANSWER
if [ "$ANSWER" = yes -o "$ANSWER = Yes -o "$ANSWER = YES -o "$ANSWER = y ] ; then echo "Yes... Entered" elif [ "$ANSWER = no -o "$ANSWER = No -o "$ANSWER = No -o $ANSWER = n ] ; then echo "No.... Entered" esle echo "Answer not recongnize" exit 1 fi |
[예제3] /etc/init.d/atd 시작 스크립트 예제
다음은 volume management daemon(vold)을 관리할 때 사용하는 스크립트이다.(Solaris 10 버전)
시작 스크립트(Startup Script)을 분석해 보자.
# vi /etc/init.d/atd
#!/bin/bash # # /etc/rc.d/init.d/atd # # Starts the at daemon # # chkconfig: 345 95 5 # description: Runs commands scheduled by the at command at the time \ # specified when at was run, and runs batch commands when the load \ # average is low enough. # processname: atd # Source function library. . /etc/init.d/functions # pull in sysconfig settings [ -f /etc/sysconfig/atd ] && . /etc/sysconfig/atd test -x /usr/sbin/atd || exit 0 RETVAL=0 # # See how we were called. # prog="atd" start() { # Check if atd is already running if [ ! -f /var/lock/subsys/atd ]; then echo -n $"Starting $prog: " daemon /usr/sbin/atd $OPTS && success || failure RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/atd echo fi return $RETVAL } stop() { echo -n $"Stopping $prog: " killproc /usr/sbin/atd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/atd echo return $RETVAL } restart() { stop start } reload() { restart } status_at() { status /usr/sbin/atd } case "$1" in start) start ;; stop) stop ;; reload|restart) restart ;; condrestart) if [ -f /var/lock/subsys/atd ]; then restart fi ;; status) status_at ;; *) echo $"Usage: $0 {start|stop|restart|condrestart|status}" exit 1 esac exit $? exit $RETVAL
|
(Key Point) (ㄱ) case ~ in ~ esac 구문에서 에러 처리 부분
# /etc/init.d/atd start
atd starting. |
-> atd 데몬이 뜬다.
# /etc/init.d/atd stop
-> atd 데몬이 종료 된다.
# /etc/init.d/atd
Usage: /etc/init.d/atd { start | stop } |
[예제4] here 문서와 case 명령어를 이용한 메뉴 구성
here 문서와 case 명령어는 함께 쓰이는 경우가 많다. here 문서는 화면에 출력될 메뉴를 구성하는데 쓰며, case 명령어는 사용자의 선택을 검사하여 적절한 메뉴 항목을 수행한다.
# cat sample_profile.sh
#!/bin/ksh
cat << EOF 1) vt100 2) xterm 3) sun <= Here Documnetation 4) dtterm EOF
echo -n "Enter Your Choice?[1-4] : " read CHOICE
case "$CHOICE" in 1) TERM=vt100 ;; 2) TERM=xterm ;; 3) TERM=sun ;; 4) TERM=dtterm;; *) TERM=vt100 ;; esac
export TERM echo "TERM is $TERM" |
(Key Point) (ㄱ) Here Documentation 사용한 메뉴 구성(ㄴ) Here Documentation + cas ~ in ~ esac 구문
# chmod +x sample_profile.sh
# ./sample_profile.sh
1) vt100 2) xterm 3) sun 4) dtterm Enter Your Choice? [1-4]: 2 TERM is xterm |
[예제5] 운영체제 종류 및 버전 선택
다음은 운영체제에 맞는 명령어들을 수행할 수 있도록 하는 예제이다. 운영체제의 종류에 따라 명령어가 틀린 경우가 있다. 이런 경우 운영체제 종류에 따라서 다른 명령어가 수행 될수 있도록 스크립트를 작성한다.
# cat os_type.sh
#!/bin/ksh
OS=`uname -s` uname -s <= 운영체제 종류가 출력됨
case $OS in HP-UX) CMD=bdf ;; <= HP-UX는 df명령어가 없어서 bdf라는 명령어가 대체한다. *) CMD="df -k" ;; <= 여러 플랫폼에서 동작할 수 있도록 bdf가 없을때 대체 명령어 esac
$CMD |
(Key Point) (ㄱ) 이기종간(다른 종류의 여러 운영체제)의 호환성 스크립트 작성
# chmod +x os_type.sh
# ./os_type.sh
Filesystem kbytes used avail capacity Mounted on /dev/dsk/c0t2d0s0 15699194 8726068 6816135 57% / /devices 0 0 0 0% /devices ctfs 0 0 0 0% /system/contract proc 0 0 0 0% /proc mnttab 0 0 0 0% /etc/mnttab swap 1869656 1680 1867976 1% /etc/svc/volatile objfs 0 0 0 0% /system/object sharefs 0 0 0 0% /etc/dfs/sharetab fd 0 0 0 0% /dev/fd swap 1868128 152 1867976 1% /tmp swap 1868032 56 1867976 1% /var/run /dev/dsk/c0t2d0s3 481575 1041 432377 1% /data1 /dev/dsk/c0t2d0s4 481575 1041 432377 1% /data2 /dev/dsk/c0t2d0s7 481575 1051 432367 1% /export/home |
운영체제의 버전을 선택할 수 있도록 하는 예제이다. 운영체제의 버전의 종류에 따라서 다른 명령어가 수행되는 경우가 있다. 이런 경우 운영체제 버전의 종류에 따라서 다른 명령어가 수행될 수 있도록 스크립트를 작성한다.
# cat os_version.sh
#!/bin/ksh
VERS=`uname -r`
case $VERS in 5.7) echo "Solaris 7 = SunOS 5.7" ;; 5.8) echo "Solaris 8 = SunOS 5.8" ;; 5.9) echo "Solaris 9 = SunOS 5.9" ;; 5.10) echo "Solaris 10 = SunOS 5.10" ;; <=버전에 따라 커맨드가 달라져서 호환가능하도록 esac |
(Key Point) (ㄱ) 운영체제 버전간의 호환성 스크립트 작성
# chmod +x os_version.sh
# ./os_version.sh
Solaris 10 = SunOS 5.10 |
'Learning > └◆Shell Scripts' 카테고리의 다른 글
[Shell Scripting] 본(Born) 쉘 프로그래밍_4 (0) | 2016.12.12 |
---|---|
[Shell Scripting] 본(Born) 쉘 프로그래밍_3 (0) | 2016.12.12 |
[Shell Scripting] 본(Born) 쉘 프로그래밍 (0) | 2016.12.12 |
[Shell Scripting] 본(Born) 쉘 특징 (0) | 2016.12.12 |