실무에서 자주 사용되는 쉘 스크립트  #6
           (요일별 차등백업 프로그램)



  지난강좌(#5)는 서버의 트래픽을 측정해 보았다.
금번 강좌에서는 서버에서 가장 중요한 백얼을 효율적으로 할 수 있는 프로그램을 만들어 보겠다. 서버 장애/삭제등의 이유로 데이터를 잃게 된다면, 가장 힘이 되는 것은 백업이다.

다음과 같은 상황을 고려하여 프로그램을 만들어 갈 것이다.
  1. 매일 백업을 한다.
  2. 데이터는 일주일간 유지되어야 하다.
    ( 토요일에 데이터가 없어진것을 화요일에 발견해도 금요일 데이터로 복원가능해야 한다.)
  3. 데이터 양이 많아 변경(추가/삭제/수정)된 부분만 백업하려 한다.

위 조건을 만족하는 프로그램을 만들어보자~



1) 차등백업을 한다?
  차등이란 변경(추가/삭제/수정)된 파일 및 디렉토리만을 백업하는 것을 말한다.
그래도 비교 대상 데이터가 있어야 하기 때문에 최초 1회는 full 백업할 것이다.
처음 모든것을 가져오고 시간이 지난다음 그것과 비교하여 변경된 것을 가져온다. #$@#$@%
아주 복잡하다... 하지만 하나의 명령어면 우리의 고민을 해결해 줄 수 있다.


  (1) rsync명령어를 알자!
    rsync -av /home/  /backup/home/

  위 명령어를 내리면, /home/ 디렉토리의 모든 파일 및 디렉토리를 /backup/home/ 에 모두 복사해 준다. 권한, 소유자 등 모든 것을 똑같이 복사해 준다.

   한번더, 명령어를 내리면 추가된 파일이, 수정된 파일이 있으면 복사해 준다.
하지만, 원본에서 지우면 사본에서는 지워지지 않는다.


  (2) 원본에서 지워지면, 사본에서도 지워라!
    rsync -av --delete /home/  /backup/home/

  위 명령어를 내리면, 원본에서 지워졌다면 사본에서도 지워진다.
 --delete 옵션이 바로 그런 역할을 한다.


이렇게 하면, 우리가 고민하던 것을 말끔히 해결해 준다. 모든 파일을 동일하게^^



 
2) 어떻게 누적 백업 할까?
  누적 백업? 일주일간 누적? rsync명령어로는 원본과 사본을 유지 할 수 밖에 없다.
  어떤 방법이 좋을까? 여러가지 방법이 있겠지만, 가장 효율적인 방법이라 생각한 것이 요일별로 디렉토리를 만들어 차등백업 하는 것이다.

  (1) 요일별로 디렉토리를 만들자
     
     export LANG=en
     week="`date '+%A'`"

     mkdir -p /backup/$week

   일단, 언어를 영어로 한다. 디렉토리는 한글을 사용하지 않는 것이 좋다.
 위급한 상황에 리눅스콘솔에서 한글파일및 디렉토리명을 지원하지 않을 수 있기 때문이다.

   오늘은 무슨요일? date 에서 '%A'는 요일을 의미한다. Friday 이렇게 나온다^^
  그런다음, mkdir으로  디렉토리를 만들어 주면 끝^^


  (2) 요일별 차등백업
     위에서 만든 디렉토리에 rsync명령으로 백업하면..

     export LANG=en
     week="`date '+%A'`"

     mkdir -p /backup/$week
     rsync -av --delete /home/  /backup/$week/home/

   위 명령어를 내리면 백업이 될 것이다.!!


  (3) 앗! 디렉토리가 이미 있다면 에러가 난다~
     export LANG=en
     week="`date '+%A'`"

     if [ ! -d "/backup/$week/home/" ] ; then
        mkdir -p /backup/$week/home/
     fi
     rsync -av --delete /home/  /backup/$week/home/

     이렇게 하면 디렉토리가 없다면, 만들어서 백업해 줄것이다.



3) 여러개의 백업 디렉토리가 있다면?
  지금까지 예제에서는 /home/ 디렉토리를 대상으로 했다. 하지만 서버에는 수 많은 백업대상이 있다. 그럴 때 마다 위와같이 줄~줄 나열하는 것은 비효율적이다.
 이제! 함수라는 것을 배워보자~

  (1) 함수(function)
  모든 언어에는 함수가 존재한다. 일부 언어에는 프로시져와 함수를 달리 사용하기도 한다.
 하지만, bash쉘에서는 함수만 제공한다.
   함수는 어떤 일의 단위로 작성하기도 하고, 반복되는 루틴을 작성하여 효율적으로 사용하기도 한다.  함수에 대한 자세한 설명은 본 강좌에서 하지 않겠다.


  (2) 함수의 적용
   function sum {
     echo $(($1+$2))
   }

  sum 1 2


 위 예는 간단한 함수를 만들었다.  함수에 2개의 파라미터를 넣어서 더하게 하는 함수이다.
sum 1 2 이렇게 하면 결과는 3이 출력된다. bash에서 함수는 명령어의 형식과 같다.  함수명 뒤에 나오는 것이 파라미터 1번, 두번째 나오는 것이 파라미터 2번이다. 함수 내에서도 $1은 파라미터 1번, $2는 파라미터 2번이 된다. 다른 언어와 같이 파라미터 갯수를 미리 선언할 필요 없다. 명령어의 인자와 같이 넘겨서 처리 하기만 하면 된다.


  (3) 백업 프로그램에 함수 사용
 
    export LANG=en
    week="`date '+%A'`"
    backup_dir="/backup/$week"

    function sync_bak {
      from=$1
      to=$2
      if [ ! -d "$to" ] ; then mkdir -p $to ; fi
      rsync -av --delete $from $to
    }

    sync_bak /home/ $backup_dir/home/
    sync_bak /usr/local/mysql/data/ $backup_dir/mysql-data/


함수를 사용하여 우리 프로그램을 위와 같이 완성하였다.

sync_bak 함수를 만들었고, 그 파라미터는 백업대상과 백업할 곳을 넣었다.
그리고 백업 할 곳이 없으면, 만들게 했다.

위 프로그램에서는 /home/과 /usr/local/mysql/data/를 백업하고 있다.
물론 더 많다면 비슷한 형식으로 기술해 주면 된다.^^

  위 프로그램 작성후 cron에 등록해 하루에 한번씩 실행하면,
우리가 원하는 결론은 얻은 것이다.^^



위 쉘스크립트로  원하는 디렉토리를 원하는 장소에 백업 할 수 있을 것이다.
일주일간 누적보관하기 때문에 매우 좋다.^^ 단, 백업 디스크 용량이 큰것이 필요하겠다.~~~



우리는 이것으로
 가장힘이 되는 백업을 효율적으로 할 수 있는 프로그램을 만들었다. 위 스크립트를 작성하면서
date, rsync, mkdir 명령어  및  함수, 파라미터 $1, 변수, if
, export  문을 알게 되었다.
 잘 만들어진 백업 스크립트로 안전한 서버 운영을 하게 되었다. 작은행복^^

'OS > LINUX' 카테고리의 다른 글

Perl 입문  (0) 2011.05.17
프로세스 - fork & exec  (0) 2011.05.14
쉘스크립트 ex5  (0) 2011.05.14
쉘스크립트 Ex4  (0) 2011.05.14
쉘스크립트 Example2  (0) 2011.05.14
실무에서 자주 사용되는 쉘 스크립트  #5
           (트래픽 점검(측정) 유틸리티)



  지난강좌(#4)는 ping을 이용하여 여러 서버를 점검하는 스크립트를 만들어 보았다.
금번 강좌에서는 서버의 트래픽을 간단하게 확인 할 수 있는 트래픽 측정 유틸리티를 만들어 보도록 하겠다. 우리가 흔히 얘기하는 트래픽은 초당 얼마나 많은 데이터들이 소통되는지를 의미한다. 트래픽의 단위는 대부분 Bit/Sec로 표현한다. 원하는 목표를 달성해 보자^^

항상 그렇듯 차근 차근 문제를 풀어 보도록 하자 ...



1) 트래픽 정보를 어디에서 구할 수 있을까?
  트래픽을 측정하기 위해서는 어디에서 정보를 구해와야 한다.
트래픽.... 그렇다면 네트웍 장치와 관련이 있을 것이며, 그 정보를 /proc 에서 찾을 수 있었다.
물론 .. ifconfig 명령어를 입력하면 찾을 수 도 있다.


  (1) /proc의 트래픽 관련 정보 수집
    cat /proc/net/dev

    결과 :
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:85543370 1148565    0    0    0     0          0         0 85543370 1148565    0    0    0     0       0          0
  eth0:1829471133618 19299120632    0    0    0     0          0   1498386 14446844326628 21830048151    0    0    0     0       0          0
  eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  sit0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

  위 정보가 복잡해 보이지만, 많은 정보를 내포하고 있다.
네트웍 장치가 여러개 보이지만, eth0, eth1 이 주요 측정 대상이 되며, 숫자가 많이 적힌 eth0이 주 인터페이스인 것을 확인 할 수 있다.



  (2) 위 정보에서 eth1에 대한 정보만 수집하자.
    grep eth0 /proc/net/dev

    결과 :
  eth0:1829520748902 19299665416    0    0    0     0          0   1498445 14446945435248 21830514044    0    0    0     0       0          0

  원하는 정보를 추출 하였다. 각 값들은 여러가지 의미를 내포하지만, 우리에게 필요한 것은 인터페이스를 통해 전달된(송/수신)데이터 양이다.  1번째숫자(수신)와, 9번째 숫자(송신)만 필요하다.


  (3) 원하는 값만 뽑아 내자 (awk)
    grep eth0 /proc/net/dev | awk '{print $1}'

    결과 :
eth0:1829578744769

   첫번째 값을 뽑아 내었다. 이 값은 인터페이스가 수신한 데이터 양이다.
여기서 사용한 awk 명령어는 아주 아주 유용한 명령어이다. ㅤㅅㅞㅂ 스크립트를 작성하는데 꼭! 꼭! 필요한 명령이며 아주 많은 기능을 가지고 있다. 위 예제에서 사용한 것은 표준 입력값을 받아서 첫번째($1) 단어만 추출한 것이다. 물론 공백을 기준으로 단어를 나누게 된다.
  그런데! 앞에 장치명(eth0)이 붙은  것을 확인할 수 있다.. 제거해야 하는데..


  (4) "eth0:"를 제거해 보자 (sed)
    grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'

    결과 :

1829619555710

   eth0: 를 제거했다.
 그런데 sed 는 무엇이고 그 다음에 나오는 것은 무엇일까???
 sed는 스트림에디터 이다. 표준 입력으로 들어오는 내용을 편집 하는 것이다.
   "s/.*:// :"  s/표현1/표현2/ 를 의미하며 표현1을 표현2로 바꾸겠다는 것이다.
  ".*:"  "."은 아무 글자를 의미하고, "*"는 0개 이상을 의미한다.
 결론적으로 ":" 앞에 아무글자가 오는 것을 모두 지우라는 의미이다.
 그렇다면 생각해 보자.
   eth0:232312
 에서 eth0는 : 앞에 오는 0개 이상의 아무 글자이다 그래서 제거하면,
   232312 가 된다.^^
 

  (5) 뽑아낸 정보로 트래픽을 계산해 보자

    rx1=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
    sleep 3
    rx2=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
    rx3=$((rx2-rx1))
    echo "$rx3"

    결과 :
  352273
 
  rx1을 조사하고 3초간 기다린다.  기다리게 하기 위해 sleep 명령어를 사용하였다.
  3초후 rx2를 조사했다.  그런다음 rx2에서 rx1을 뺐다.
  bash 쉘에서 숫자 계산을 하기 위해서는 $((계산식)) 을 사용한다!! 계산식에 변수는 $를 붙이지 않는다.

  위 계산 결과는 3초 동안의 트래픽 변화양이다. 그리고 그 단위는 Byte 이다.


 
(6) KBit/Sec 단위로 변환해 보자
  rx3=$(( (rx2-rx1)/3*8/1024 ))

  위 계산식에서 3초간 조사했기에 3으로 나눴고,
  Byte를 Bit로 바꾸기 위해 8을 곱하고, Bit를 KBit로 바꾸기 위해서 1024로 나눴다.
  이미 계산할 수 있는 것은 계산하여 컴퓨터의 부하를 줄여보자.
   x*8/1024 = x*128   이 된다.
  그렇다면 계산식은

  rx3=$(( (rx2-rx1)/3*128 ))

 


2) 3초간 트래픽을 측정할 수 있는 프로그램 완성!!
 
  rx1=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx1=`grep eth0 /proc/net/dev | awk '{print $9}'`
  sleep 3
  rx2=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx2=`grep eth0 /proc/net/dev | awk '{print $9}'`

  rx3=$(((rx2-rx1)/128/3))
  tx3=$(((tx2-tx1)/128/3))

  echo "`date '+%k:%M:%S'` : $rx3 / $tx3"


  위 스크립트는 rx(수신), tx(송신) 용량을 조사하여 3초간 기다린 다음 계산하여 보여주게 만들었다.
  시간을 출력하기 위해 date 명령을 사용하였다.
 '
+%k:%M:%S' 는 시(24시) 분(60분) 초(60초)를 출력하기 위한 형식이다.



3) 계속 반복시키자
  위와같이 작성하면 1번 실행하고 끝난다. #1번 강좌에서 배웠던 while 문을 이용하여 반복시켜 보겠다.

echo "시간 : 수신(Kbit/Sec) / 송신(Kbit/Sec)"
while ( true ) ; do
  rx1=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx1=`grep eth0 /proc/net/dev | awk '{print $9}'`
  sleep 3
  rx2=`grep eth0 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx2=`grep eth0 /proc/net/dev | awk '{print $9}'`

  rx3=$(((rx2-rx1)/128/3))
  tx3=$(((tx2-tx1)/128/3))

  echo "`date '+%k:%M:%S'` : $rx3 / $tx3"
done

while 문을 사용하여 무한 반복하였다.!!
자 이렇게 하면 eth0의 트래픽을 3초간 조사하여 평균을 보여주는 프로그램을 완성하였다.!!

But!. 네트웍 장치가 eth0가 아닌 다른것이며? 3초 단위가 아닌 10초 단위로 보고 싶다면,... 그럴 때 마다 쉘 스크립트를 수정하기엔 너무 번거롭다.!!! 명령어 처럼 인자로 받아서 처리하고 싶은데......



4) 다양한 장치, 다양한 delay 시간 제공 
  프로그램이 인자를 받아서 처리 하는 것은 아주 당연한 일이다.. 쉘 스크립트와 같이 소스를 수정할 수 있으면 좋겠지만, 수정하지 못하는 컴파일된 명령어는 아주 힘든 일이다.  그럼 다음과 같이 처리해 보자!


echo "시간 : 수신(Kbit/Sec) / 송신(Kbit/Sec)"
while ( true ) ; do
  rx1=`grep $1 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx1=`grep $1 /proc/net/dev | awk '{print $9}'`
  sleep $2
  rx2=`grep $1 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx2=`grep $1 /proc/net/dev | awk '{print $9}'`

  # 1024/8 == 128
  rx3=$(((rx2-rx1)/128/$2))
  tx3=$(((tx2-tx1)/128/$2))

  echo "`date '+%k:%M:%S'` : $rx3 / $tx3"
done


a.sh 파일에 위와같이 입력하고 파일을 만든 다음.  실행권한을 주고 다음과 같이 실행한다.

./a.sh eth0 2

위와같이 입력하면, 인터페이스는 eth0를 사용하고 , delay 시간은 2초로 한 것이다.
위 쉘스크립트에서 첫번째 인자가 $1 (eth0) ,  두번째 인자가 $2 (2) 인것이다.!!



5) 다른 사람들도 쓰게 하자!
 '4)' 와 같이 작성하면, 명령어의 인자가 있다는 사실을 아는 사람은 작성한 사람 또는 쉘 스크립트를 본 사람만이 알 수 있다. 사람의 머리는 시간이 지나면 잊어 먹기 마련이다. 작성한 사람조차 뭘 넣어야 잘 작동할지 모른다.  다음과 같이 개선해 보자.


if [ "$1" == "" ] ; then
  echo "사용법 : $0 장치명 [delay]"
  echo "예) $0 eth0 3 "
  exit 1
fi
if [ "$2" == "" ] ; then delay=3 ; else delay=$2 ; fi

echo "시간 : 수신(Kbit/Sec) / 송신(Kbit/Sec)"
while ( true ) ; do
  rx1=`grep $1 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx1=`grep $1 /proc/net/dev | awk '{print $9}'`
  sleep $delay
  rx2=`grep $1 /proc/net/dev | awk '{print $1}' | sed 's/.*://'`
  tx2=`grep $1 /proc/net/dev | awk '{print $9}'`

  # 1024/8 == 128
  rx3=$(((rx2-rx1)/128/delay))
  tx3=$(((tx2-tx1)/128/delay))

  echo "`date '+%k:%M:%S'` : $rx3 / $tx3"
done


처음에 2번째 인자($2)를 조사하여 아무것도 없으면, 즉 입력이 되지 않았다면, 메시지를 뿌려준다.
 $0는 실행한 프로그램 그 자체 파일명을 의미한다. exit 1는 리턴값 1을 반환하면서 종료하게 되는 것이다.

그리고 delay 시간은 있어도 되고 없어도 되게 하며, 기본값은 3으로 하였다.
3번째 인자($3)를 조사하여 없으면 $delay변수에 3을 넣고, 있으면 그 값을 넣어준다.



위 쉘스크립트를 이용하여 사용하고 서버의 트래픽을 점검 할 수 있다.


우리는 이것으로
 아주 쉽게 트래픽을 확인 할 수 잇는 프로그램을 만들었다. 위 스크립트를 작성하면서
awk, grep, sed, sleep명령어  및 숫자 계산 $(()), 아규먼트 $1 , while, if, exit 문을 알게 되었다.
  서버에 간단한 유틸리티를 깔아 놓음으로 트래픽을 바로 확인 할 수 있게 되었다. MRTG에서 그래프를 보려면 많이 기다려야 하는데.. 답답하지 않고 좋다^^ 넘넘 뿌듯하다^^..

'OS > LINUX' 카테고리의 다른 글

프로세스 - fork & exec  (0) 2011.05.14
쉘 스크립트 #6  (0) 2011.05.14
쉘스크립트 Ex4  (0) 2011.05.14
쉘스크립트 Example2  (0) 2011.05.14
쉘스크립트 example  (0) 2011.05.14
실무에서 자주 사용되는 쉘 스크립트  #4
           (ping을 이용한 서버 모니터링)




  지난강좌(#3)는 MySQL에 관련된 편리한 스크립트를 만들어 보았다.
금번 강좌에서는 ping명령을 이용하여 나의 서버들을 관리할 수 있는 서버모니터링 프로그램을 만들어 보도록 하겠다. ping 명령어를 이용하여 단순하게 테스트를 할 것이다.
  단순히 한 서버만 ping 테스트 한다면 좋겠지만, 내가 관리하는 서버가 여러대라면, 하나 하나 하기엔 힘든 일이다. 쉘스크립트를 이용하여 많은 서버를 관리 할 수 있도록 만들어 보겠다.


먼저, 어떤일을 할 것인지 생각 해 보자...



1) ping 명령어로 서버를 점검한다?
  ping 명령어로 서버가 죽었는지 살았는지 확인 할 수 있다. 물론 서버나 네트웍 장비에서 ping을 막는다면, 불가능 한 일이지만, 그렇지 않다는 가정하에서 ping 명령어를 이용하겠다.

  (1) 서버 점검
    ping 아이피

  위와같이 명령어를 입력하면, 정상적 이라면, 지속적으로 응답시간을 보여 주게된다.


  (2) ping을 한번만 테스트 하려면?
    ping -c 1  아이피

    이렇게 하면, ping 테스트를 한번만 한다. 정상적일 때는 응답이 빠른데 실패는 너무 느리다.


  (3) ping 테스트시 응답을 기다리는 시간을 줄이려면?
    ping -c 1 -w 1 아이피

   위와같이 하면, 응답이 없더라도 1초만 기다리게 된다.


  이제 ping 명령으로 특정 서버를 점검할 준비가 되었다. 




2) 서버의 응답 결과를 쉘에서 처리하자!
  ping 명령의 결과는 사용자가 보기 좋은 형태로 나타난다. 하지만, 프로그램을 작성하기 위해서는 단순하게 "된다" 혹은 "안된다" 정도가 편리하다. 모든 명령어는 명령어 실행 결과를 리턴하게 되어 있다. 대부분 정상적으로 작동하였으면 0 , 아니면 에러코드 를 리턴한다.

  bash쉘에서 바로 전 명령어의 리턴값을 받아오는 변수가 있다 "$?"  이다.
 이 변수를 가지고 다음과 같이 ping 명령의 결과를 처리 할 수 있다.

 
ping -c 1 -w 1 아이피 &> /dev/null
  if [ "$?" == "0" ] ; then
     echo "정상"
  else
     echo "비정상"
  fi


 위 명령으로 ping 결과에 대한 리턴값을 받게 되며, 결과값이 0이면 "정상"을 출력하고 아니면, "비정상"을 출력하게 된다.
  ping 명령어의 출력은 /dev/null으로 보내 버린다^^



3) 서버 리스트를 입력하자
   내 서버가 여러대라면, 서버 리스트를 입력해야 한다. 여기서는 쉘스크립트의 배열을 사용하도록 한다.
 
  (1) 배열을 입력한다.
    server[0]="192.168.0.100"
    server[1]="192.168.0.1"

위와같이 배열으로 선언했다.
server 라는 배열에 0번째 주소에서는 "192.168.0.100"
server 라는 배열에 1번째 주소에서는 "192.168.0.100"

서버가 많이 있다면, 많이 넣어주면 된다.^^


  (2) 배열의 내용을 보여준다.
     echo ${server[0]}

위와같이 출력할 수 있다.


  (3) 배열의 크기가 궁금하다?
    echo ${#server[*]}


  (4) 배열의 모든 내용을 출력하려면?
    echo ${server[*]}


우리는 이렇게 서버 리스트를 배열에 넣었고 데이터를 확인 했다.



4) '3)'에서 넣었던 데이터를 '2)'의 ping 명령으로 점검해 보도록 하자!
  이제 반복문 인 for 문을 알아 보자.  #3 강좌에서는 for in 문을 배웠지만, 지금 사용하는 for 문은 일반적인 언어에 있는 for 문이다. c 언어의 그것과 비슷하니 살펴 보도록 하자.


for (( 표현식1 ; 표현식2 ; 표현식3 )) ; do
  <명령어들>
done

일반적인 언어와 같이 "표현식1"은 초기에 1번만 실행된다.
"표현식2"는 조건문이 들어간다.
"표현식3"은 증감문이 들어간다.

다음 예제를 보자

for (( i=1 ; i<=10 ; i++ )) ; do
  echo "$i"
done

위 예는 1부터 10까지 1씩 증가하면서 출력하는 프로그램이다.




그렇다면, '3)'에서 넣었던 서버리스트를 '2)'의 명령어로 점검해 보자.

for (( i=0 ; i<${#server[*]} ; i++ )) ; do
  ping -c 1 -w 1
${server[$i]}  &> /dev/null
  if [ "$?" == "0" ] ; then
    echo "${server[$i]}  .. 정상"
  else
    echo "${server[$i]}  .. 비정상"
  fi
done


위와같이 하면, 0번부터 배열의 크기만큼 반복해서 ping 테스트를 하고,
 결과를 서버 IP와 함께 정상 / 비정상 보여 준다.




5) 우리의 목적을 달성해 보자..
 위에서 알아본 것들을 응용해서 다음과 같이 우리가 원하는 쉘스크립트를 만들어 보자.

server[0]="192.168.0.100"
server[1]="192.168.0.1"


for (( i=0 ; i<${#server[*]} ; i++ )) ; do
  ping -c 1 -w 1
${server[$i]} &> /dev/null
  if [ "$?" == "0" ] ; then
    echo "${server[$i]}  .. 정상"
  else
    echo "${server[$i]}  .. 비정상"
  fi
done


위 쉘스크립트를 이용하여 간단하게 서버가 죽었는지 살아 있는지 점검 할 수 있다.



우리는 이것으로
 아주 쉽게 서버를 점검 할 수 있는 프로그램을 만들었다. 우리는 위 스크립트를 작성하면서 ping명령어 배열, if, for 문을 알게 되었다.
 서버가 100대라면 100번 입력하지 않아도 간단한 스크립트 하나로 점검할 수 있다. 난 시간을 save 했다!!   넘넘 뿌듯하다^^..

'OS > LINUX' 카테고리의 다른 글

쉘 스크립트 #6  (0) 2011.05.14
쉘스크립트 ex5  (0) 2011.05.14
쉘스크립트 Example2  (0) 2011.05.14
쉘스크립트 example  (0) 2011.05.14
egrep , awk  (0) 2011.05.14
실무에서 자주 사용되는 쉘 스크립트  #2
           (MySQL DB관리 유틸리티)




  지난번, 강좌(apache 자동 재 시작 프로그램)에 이어 실무에서 자주 사용되는 쉘 스크립트에 대한 강좌를 써 내려 가겠다. 물론 최대한 쉽고 최소한의 라인 수로 작성 가능한 쉘 스크립트에 대한 강좌를 쓸 것이다.
   금번 강좌는 MySQL을 쉽게 관리 할 수 있는 툴이다. 서버 관리를 하다 보면, mysql 접속하여 여러가지 sql문으로 서버 상태를 알아 보거나, 모니터링 해야 할 때가 있다. 이럴 때 마다 로그인을 해서, sql문을 얻어내는 것은 아주 귀찮은 일이고, 또 익숙하지 않으면 아주 오랜 시간이 소요되는 작업이다.  내가 만들고자 하는 스크립트는 이런 작업을 쉽게 해 줄 수 있는 스크립트를 만드는 것이다.

먼저, 어떤일을 할 것인지 생각 해 보자...


1) MySQL의 프로세스 리스트를 보려면?
   mysql의 프로세스 리스트는 ps 등의 명령어로 쉽게 볼 수 있다. 난 그런 것을 원하는 것이 아니고, 각 프로세스들이 하는 일들을 보고 싶다. mysql은 다음과 같은 방법으로 이런 일이 가능하게 제공한다.
 
   mysqladmin -u root -p processlist

또는

   mysql 접속한 상태에서
   show processlist;

나는 일괄적으로 다음과 같은 방법으로 mysql 명령을 실행 시킬 것이다.

echo "쿼리;" | mysql -u"root" -p"비밀번호"

위 명령어는 다음과 같다.
 echo "쿼리; " : "쿼리;"를 출력한다.
| : 파이프, 앞 명령어의 내용을 뒷 명령어의 표준 입력으로 넣는다.
mysql -u"root" -p"비밀번호" : mysql 서버에 접속한다. "비밀번호"는 서버의 비밀번호를 넣어준다.

우리가 원하는 일은 다음과 같이 한다.

echo "show processlist;" | mysql -u"root" -p"비밀번호"





 2) root로 그냥 접속만 하려면?
  '1)'의 프로세스 리스트를 보는 것 보다 쉽다. 단순하게..

mysql -u"root" -p"비밀번호"


이렇게만 하면 끝난다.



 3) MySQL에 존재하는 database 들을 보려면?
  '1)'의 프로세스 리스트를 응용하면,

echo "show databases;" | mysql -u"root" -p"비밀번호"

이렇게만 하면 끝난다.


 이정도 했으면, 원하는 쿼리들을 위와 같은 방법으로 자유롭게 추가 할 수 있을 것이다.
내가 원하는 것은 위 명령어들을 모아서 쓰기 편리한 메뉴 방식으로 만드는 것이다.
어떻게 할까???
  나는 키보드로 특정 문자들을 입력받아 변수에 넣을 것이다. 그리고 그 변수에 따라 위 명령어들을 실행 시킬 것이다. 이런 작업들을 특정 문자가 입력될 때 까지 반속 할 것이다.



 4) 쉘 프로그램에서 키보드 입력 받기
 
나는 쉘 프로그램에서 키보드로 입력을 받아서 변수에 넣을 것이다. 어떻게 해야 할까

read <변수>
 
no라는 변수에 입력값을 넣으려면 다음과 같이 한다.
read no

이렇게 하면, '엔터'키를 누를 때 까지 입력을 받는다.

read no
echo "$no"

위와같이 하면 간단하게 입력받은 문자를 출력해서 보여 줄 수 있다.


5) 입력된 문자에 따라서 프로그램 실행 시키기
  '4)'에서 입력받은 문자에 따라서, 프로그램을 실행시키기 위해서는 case문을 사용해야 한다.
다음과 같다.

case <변수> in
   "값" )
        <명령어> ;;
   "값" )
        <명령어> ;;
 esac

위와같다.
위 방법을 우리가 목표 하는 것에 적용 시키면.

먼저 메시지를 뿌려 준다.

echo '
   1. 프로세스 리스트 보기
   2. mysql 접속
   3. database 리스트 보기
'
echo -n "번호 선택 : "
read no

case $no in
   "1" )
       
echo "show processlist;" | mysql -u"root" -p"비밀번호" ;;
   "2" )
       
mysql -u"root" -p"비밀번호" ;;
   "3" )
       
echo "show databases;" | mysql -u"root" -p"비밀번호" ;;
 esac


위와같이 작성하면, 위 쉘 스크립트를 실행 시키면, 리스트가 나오며 입력 대기 할 것이고, 1,2,3 중 하나의 번호를 누르면 지정 명령어가 실행 될 것이다..
  그렇다면, 다른 문자를 입력하면??  조건에 만족하는 문자가 없으면 그냥 지나간다...



6) 실행이 끝나면 다시 메뉴 보여주기
  명령어를 실행 시키고 빠져 나가 버리면, 다른 메뉴를 선택하기 위해서 또 명령어를 실행시켜야 한다. 하나의 명령어 실행 시키고 다시 메뉴 리스트를 반복적으로 보여 주기 위해서는 이전 강좌에서 배웠던, while 문을 사용하여 계속 실행 시키도록 해 보자.

while ( true ) ; do
  <프로그램>
done

위와같은 문법을 우리 스크립트에 적용하면,

while ( true ) ; do
   clean
   echo '
    1. 프로세스 리스트 보기
    2. mysql 접속
    3. database 리스트 보기
'
   echo -n "번호 선택 : "
   read no

  
case $no in
     "1" )
         
echo "show processlist;" | mysql -u"root" -p"비밀번호" ;;
     "2" )
         
mysql -u"root" -p"비밀번호" ;;
     "3" )
         
echo "show databases;" | mysql -u"root" -p"비밀번호" ;;
   esac
done


이렇게 하면, 선택한 명령어 실행이 끝나면, 다시 메뉴를 보여 줄 것이다.
clear 명령어는 화면의 내용을 지우라는 명령어이다. 메뉴가 줄줄줄~~ 내러 가는 일을 방지하기 위함니다.




7) 이 반복 메뉴에서 빠져 나오려면??
  한 명령어 실행이 끝나면, 메뉴가 나올 것이다. Ctrl + C 키를 눌러 빠져 나올 수 있지만, 그건 좀 아닌 것 같은데... 하나의 항목을 추가 했다. 메뉴에서 'q'키를 누르면 빠져 나오게 한다.



while ( true ) ; do
   clean
   echo '
    1. 프로세스 리스트 보기
    2. mysql 접속
    3. database 리스트 보기
    q. 끝내기
'
   echo -n "번호 선택 : "
   read no

  
case $no in
     "1" )
         
echo "show processlist;" | mysql -u"root" -p"비밀번호" ;;
     "2" )
         
mysql -u"root" -p"비밀번호" ;;
     "3" )
         
echo "show databases;" | mysql -u"root" -p"비밀번호" ;;
     "q" )
          exit 0 ;;

   esac
done


위 쉘스크립트에서 'q'키를 누르면 exit 명령어를 실행시켜 빠져 나오게 된다. 물론 정상 종료이기 때문에 0을 리턴한다..




8) "비밀번호"가 바뀌면 다 고쳐 줘야 하나요??
  비밀번호가 바뀌면 위 스크립트에서 "비밀번호" 부분을 모두 수정해야 한다. vi 등의 에디터에 치환 기능이 있어 한번에 치환 한다면 문제가 없다. 하지만, 비밀번호가 'mysql' 이라면, 얘기는 달라진다,.. 명령어인 'mysql'이 함께 바뀌기 때문에.. 하나 하나 수작업으로 고쳐야 한다.
  변수라는 개념을 써서 이 부분을 해결 해 보자.

a="변수"
echo $a

이렇게 하면 출력값은 ? 

변수

위와같이 출력된다. 변수라는 개념을 우리의 쉘스크립트에 적용시키면?

mysqlpw="비밀번호"

while ( true ) ; do
   clean
   echo '
    1. 프로세스 리스트 보기
    2. mysql 접속
    3. database 리스트 보기
    q. 끝내기
'
   echo -n "번호 선택 : "
   read no

  
case $no in
     "1" )
         
echo "show processlist;" | mysql -u"root" -p"$mysqlpw" ;;
     "2" )
         
mysql -u"root" -p"$mysqlpw" ;;
     "3" )
         
echo "show databases;" | mysql -u"root" -p"$mysqlpw" ;;
     "q" )
          exit 0 ;;

   esac
done

위와 같이 보라색 부분을 수정했다. 이렇게 수정하면, 상단의 변수만 수정 하면 다른 부분은 수정할 필요없이 적용되는 것이다.



우리는 이것으로
 쉘 스크립트의 case문과, 변수, 키보드로부터 입력받기 를 알게 되었다.
여러가지 편리한 기능들을 넣어 둔다면, 나만의 관리툴로 만들 수 있을 것이다. [뿌듯]

'OS > LINUX' 카테고리의 다른 글

쉘스크립트 ex5  (0) 2011.05.14
쉘스크립트 Ex4  (0) 2011.05.14
쉘스크립트 example  (0) 2011.05.14
egrep , awk  (0) 2011.05.14
YUM 사용법  (0) 2011.05.13
  리눅스 시스템을 관리하다 보면, 쉘 스크립트의 필요성을 절실히 느끼게 된다. 저자는 쉘프로그램관련 강좌(bash, awk, sed)를 쓰고 싶었다. bash문법, awk문법, sed사용법을 묶은 강좌를 만들고 싶었다.. 하지만, 이것은 나를 위한 정리일 뿐이다. 내가 정리하여 강좌를 쓴다면, 읽는 사람들은 필요하지도 않은 문법을 머리속에 넣어야 하고, 그 조합으로 실무에 적용시키기위해서 수 없이 많은 노력을 할 것이다. 이런 강좌는 필요하지 않다. 정리는 man 페이지를 보면 자세하게 나와 있다. 저자는 리눅스 시스템 관리에 자주 사용되는 쉘 스크립트를 경험담을 담아  강좌를 써 보려고 한다. 최대한 간단하게 만들어서 누구든 쉽게 써 보고 이해하기 쉽게 쉘스크립트를 만들고, 설명하려 할 것이다.

   처음 시작할 쉘 스크립트는 '아파치 자동 재시작 스크립트'이다.
서버를 계속해서 모니터링 해야 한다거나, 특정 수치를 초과 했을 때 조치를 해 줘야 하는 경우가 발생한다.  물론 그 문제점이 일어나지 않게 원인을 파악하여 처리하는 것이 가장 좋지만, 그럴 만한 시간이 없다면, 자동으로 실행되는 쉘 스크립트를 만들어서 띄워 두면 된다.

  금번 강좌에서 아파치 프로세스가 특정 수치만큼 생성 되었을 때, 아파치를 자동 재 시작 해주는 쉘 스크립트를 만들어 보도록 하겠다.

먼저, 어떤일을 할 것인지 생각 해 보자...


1) 아파치 프로세스 수를 어떻게 알지??
   기본적으로 아파치 프로세스 이름은 'httpd'이다 물론 다른 이름을 수 있다. 이 프로세스가 얼마나 떠 있는지 조사하려면?
ps
명령어가 떠 오를 것이다.
 그리고 httpd 프로세스만 잡아서  갯수를 세려면?
grep 명령어와 wc 명령어가 필요하다.

  이런 3명령어를 조합해서 결과를 만들어 보자.

  ps -e  : 현재 서버에서 실행중인 모든 프로세스들을 보여준다.

  ps -e | grep -w httpd : 현재 서버에서 실행중인 프로세스 중 httpd 문자가 포함된 프로세스만 잡아 보여준다.
    '-w' 옵션은 단어 단위 검색이다. httpds 이런 이름이 있어도 포함시키지 않겠다는 의미이다.

  ps -e | grep -w httpd |wc -l: 위에서 잡은 결과의 줄 수를 세어 준다.
  이렇게 하면 프로세스 수를 구할 수 있다.

 위 명령을 단순화 시키려면,
 pgrep -x httpd | wc -l : 'pgrep'은 프로세스이름에서 단어가 포함된 프로세스들의 pid를 얻기 위한 명령이다.
  '-x' 옵션은 'grep'의 '-w'옵션처럼 단어 단위로 검색하기 위한 옵션이다.
 


 2) 아파치를 재시작하는 방법?
  아파치 서버를 운영한다면, 이 방법은 알고 있을 것이다.
  컴파일 설치 했다면, /usr/local/apache/bin/apachectl restart
  또 다른 방법은 apachectl stop, apachectl start 등의 방법이 있으며,
  다른 방법은 아파치 프로세스를 모두 죽이고 시작하는 방법이 있을 것이다.
 pgrep -x httpd | xargs kill -9
 여기서 pgrep은 위에서 설명했고, xargs라는 명령이 뭘까?
 xargs는 표준 입력으로 받은 내용을 xargs의 인자로 기술하는 명령어(kill -9)의  인자로 넣는 명령어이다.
다음 예를 보자.

pgrep -x httpd
5598
5843

실행결과가 위와 같다면, 5598과 5843은 httpd의 PID임을 알수 있다.
위 프로세스를 모두 죽이기 위해서는

kill -9 5598
kill -9 5843

이런 명령을 내려야 하며, 100개라면 100번? 물론 killall 이라는 좋은 명령어가 있지만, 잘 죽지 않을 때는 kill 명령으로 죽여야 한다.


위와 같은 일을 쉽게 해 줄 수 있는 명령이 xargs 이다.
pgrep -x httpd  | xargs kill -9
이렇게 하면,
pgrep -x httpd 의 결과인 5598, 5843 이 자동 kill -9 명령어 뒤에 붙어 실행 되는 것이다.
이 명령어 하나면, 프로세스가 1000개라도 상관 없다^^



3) 자동으로 실행 시켜 주는 반복 작업 시작..
  만약 문제가 있는 시스템이라면, 시스템 관리자는 '1)'의 명령을 내려 프로세스를 수를 확인하고, 생각했던 수치 보다 많으면 '2)'번 명령어를 내려서 아파치를 재 시작 할 것이다. 언제 발생할지도 모르는 것 때문에 지속적으로 보고 있을 수 없고, 자리를 비울 수 도 없다.

bash 쉘에서는 반복작업을 위해서 여러가지 제어문을 제공한다.
지금 사용할 문법은 while 문이다.

 while ( 조건 ) ; do
  <문장>
 done

위 '조건'이 만족하는한  '<문장>'은 계속 실행된다.

 while ( true ) ; do
   ls
 done

위와같이 입력한다면, 계속.. 'ls'명령어를 실행 시킬 것이다.
대부분의 언어에서 그렇듯 반복문에서 빠져 나올려면, 'break' 문법이 있다.

 while ( true ) ; do
   ls
   break
 done


  4) 반복 실행하여 프로세스가 특정 수치 이상이면 아파치 재 시작
우리의 목적한 일을 할 수 있는 쉘 프로그램을 만들어 보자.

while ( true ) ; do
  if [ "`pgrep -x httpd | wc -l`" -ge "500" ] ; then
    /usr/local/apache/bin/apachectl restart
  fi   
done

이렇게 작성하면 끝!!!
  if 문은 조건을 비교하여 조건이 맞으면 then 이하의 문장을 실행한다. 문법은 다음과 같다.

  if [ 조건 ] ; then
    <문장>
  fi
 
 '조건'을 비교하기 위해서 '-ge' 를 썼다. ge(greater than or equal)이다. 크거나 같다의 의미.. 그렇다면,
 gt(크다), le(작거나 같다), lt(작다), eq(같다) 등이 있을 것이라 예상할 수 있다.


  5) 문제점 발견!!
  위 쉘 스크립트를 돌려 두니.. 너무 자주 비교해서, 쉘스크립트가 서버에 부하를 준다..
 그렇다면, sleep으로 비교 시간을 늘려 준다.

while ( true ) ; do
  if [ "`pgrep -x httpd | wc -l`" -ge "500" ] ; then
    /usr/local/apache/bin/apachectl restart
  fi   
  sleep 1
done

위와같이 'sleep 1'을 입력하였다면, 1초가 쉬어라는 것이다. 1초간 쉬었다가 다시 비교하게 된다.



우리는 이것으로 원하는 결과를 얻었다.!
이젠 지속적으로 프로세스를 수를 확인하여 아파치를 재 시작해야 하는 노가다는 하지 않아도 된다. 하하하!!



  이것으로 ' 실무에서 자주 사용되는 쉘 스크립트  #1' 강좌를 마무리 하겠습니다.
본 강좌의 설명이 어렵거나, 잘못된 부분이 있으면 언제든지 따끔한 지적을 바랍니다.

'OS > LINUX' 카테고리의 다른 글

쉘스크립트 Ex4  (0) 2011.05.14
쉘스크립트 Example2  (0) 2011.05.14
egrep , awk  (0) 2011.05.14
YUM 사용법  (0) 2011.05.13
vi 사용하기  (0) 2011.05.03

+ Recent posts