Shell Script For System Administrator

Bookmark and Share

유닉스는 물론, 리눅스 시스템 관리자/운영자들에게 쉘 스크립트의 활용은 가장 기본적인 기술이면서, 동시에 가장 아름다운 기술이기도 하다. 이 글, 시스템 관리자를 위한 쉘 스크립트는 지금 나와 함께 일하는 동료들을 위한 IT이야기의 첫번째 주제이다.

쉘 스크립트 작성에 대해 이야기하기 전에, 다음의 글을 읽어보기를 권한다. 이 글을 쓰기 시작하면서 작성한 "시스템 엔지니어가 왜 프로그래밍을 배워야 하는지"에 대한 나의 생각이다.

프로그래밍을 배워야해요? 난 시스템 운영자인데...

환경의 이해

빨리 본론으로 들어가면 좋으련만, 나는 서론이 좀 길다. 기능적인 지식 습득보다는 배경과 환경의 이해가 실질적인 실력향상으로 이어진다는 믿음 때문인데, 좀 장황하게 말하면, 당장 기능을 습득하고 예제를 참고하여 단기간 내에 한 편의 스크립트를 작성할 수 있게 된다고 하더라도 실무 중 만날 수 있는 어떤 상황에서 그 상황과 조건에 맞는 해법을 찾기 위해서는 명령어, 구문 몇 개보다 절실한 것이 환경의 이해라는 것을 경험 속에서 느끼고 있기 때문이다.

환경의 이해가 실력 향상의 기본!

이 장에서는 쉘스크립트가 동작하는 환경 또는 쉘스크립트를 필요로 하는 환경에 대하여 (리눅스를 포함한) 유닉스의 기본, 프로그램의 생명주기, 그리고 실행환경으로 나누어 꼭 필요한 부분만 간단히, 약간의 살과 함께 살펴보려고 한다.

유닉스 기본

UNIX는 아주 오래 전에(1970년대면 아주 오래전이 맞나?) 만들어진, 그러나 그 체계적 완성도 등으로 인하여 아직까지도 많이 사용될 뿐만 아니라 그 이후의 많은 OS 개발의 Reference가 된 OS이다.

UNIX라는 이름은 그것이 파생되어 나온 Multics라는 OS 개발 프로젝트의 이름을 장난스럽게 꼬아 만들어진 이름이다. 그러나 이름이 UNI- 인 것과는 다르게 UNIX는 다중 사용자(Multi-User), 다중 프로세스(Multi-Process) 시스템으로, 하나의 기계를 동시에 여러 명이 달라 붙어서 여러가지 일을 동시에 수행시킬 수 있는 시분할 방식의 시스템이다.

유닉스는 여러 프로세스를 동시에 실행시킬 수 있는 Multi-Process 시스템!

이 장의 주제에서 조금 멀어지는 감이 있지만, 시간이 되면 OS의 기본 구성요소인 Kernel, Shell, Utility 등에 대하여 살펴보면 더욱 좋겠다.

프로그램, 실행, 프로세스

유닉스가 멀티 프로세스 시스템이라고 말했는데, 그럼 프로세스는 무엇인가? 너무 쉬운 얘기를 하고 있나? 아무튼,

사람이 컴퓨터라는 고철 조가리와 구리선과 프라스틱, 그리고 약간의 금박 등으로 이루어진 컴퓨터에게 일을 시키는 과정은 다음과 같은 생명주기를 통하여 이루어진다.

  1. 사람이 쓰고 읽고 해석할 수 있는 형식으로 저장된 논리. 이름하여 Source
  2. 사람의 언어를 컴퓨터의 표현으로 바꾸는 Compile, 그 결과인 Object
  3. 컴파일된 기계어 Object를 공용 라이브러리와 연결하는 Link
  4. Compile과 Link 단계를 거쳐 OS가 해석할 수 있는 모양으로 저장된 Executable
  5. Executable이 디스크로부터 읽어져 메모리 공간을 차지하고 올라간 Process

C 등의 언어로 작성되어 우리가 많이 사용하는 대부분의 명령어, 프로그램 들은 위와 같은 절차에 의해, 메모리에 올리면 바로 실행이 가능한 형태로 존재하게 된다. (리눅스에서는 ELF라는 형식의 Binary 포맷을 사용한다.)

그리고 표준 C 라이브러리를 비롯하여 다양한 공용 라이브러리(shared library, Windows 개념으로는 DLL)를 사용하기 때문에 개발을 하는 사람은 일반적인 많은 부분을 라이브러리에 의존하여 "사용"하게 되고, 자신의 노력은 "문제의 해법"에 집중하게 된다.

그러나, 우리가 지금 익히려 하는 쉘스크립트는,

  1. Compile과 Link를 하지 않으며 사람이 쓴 그 형태 그대로 Disk에 살게 되며,
  2. 커널에 의해 단독실행되지 않고 해석기(Interpreter)를 통하여 구동되는

특징을 갖는다. 물론, 여기서 Interpreter는 Bash, Tcsh 등의 쉘이며, 이렇게 Interpreter에 의존적인 쉘스크립트1는, 해당 스크립트의 문법을 이해하는 해석기인 쉘이 있어야 실행이 가능하다. 또한 컴파일은 물론 링크를 거치지 않기 때문에 공용 라이브러리의 활용은 없으나, 대신 다양한 유닉스 유틸리티의 기능을 활용하게 된다.

아무튼, (C Programming 과정이라면 이 부분을 좀 더 파야하는데…)

쉘스크립트는 해석기(쉘)에 의존적이며, 다양한 미니 유틸리티로부터 힘을 얻는다.

좀 다른 얘기지만, 여기서 다시 "작은 일 하나라도 제대로 하라"는, 그리고 "여럿이서 함께 하라"는 유닉스 철학이 번쩍인다. 관심이 있으면 다음 Page가 도움이 될 것이다.

http://en.wikipedia.org/wiki/Unix_philosophy

  1. Small is beautiful.
  2. Make each program do one thing well.

40년 된 노익장을 과시하는 유닉스의… 철학적 완성도와 저력이 보이는 대목이 아닌가?

실행환경

이제 스크립트를 둘러싼 재미있는 이야기는 거의 끝난 것 같다. 이 장의 마지막 절에서는, 이러한 배경과 환경들이 어떻게 쉘스크립트의 실행 환경에 뭍어있는지, 보다 피부에 와닿는 부분을 잠깐 보려고 한다.

쉘은 실행 형태에 따라 대화형 쉘(Interactive Shell)과 비대화형 쉘(None-Interactive Shell)로 크게 나뉜다. 그리고 다시 대화형 쉘의 경우, 로그인 쉘과 일반 대화형 쉘로 나뉘게 된다. 우리의 스크립트는, 일반적으로 비대화형 쉘의 지배하에 있다.

쉘이 위의 세 가지 형태 중 어떤 형태로 실행되어지는지에 따라서, 그것이 시작할 때 하는 행동을 포함한 몇가지 점에서 차이점을 가지고 있다. 이러한 차이는, 스크립트 작성을 처음 시작한 사람으로 하여금 이따금 혼돈에 빠지게 만드는 경우가 있으므로 이 부분에 대하여 잘 이해할 필요가 있다. (여기서는 간단히 필수적인 부분만 알아볼 것이며, 상세한 이야기는 bash 등의 man page에서 INVOCATION 절을 찾아서 찬찬히 읽어보면 도움이 된다.)

shell type

sourcing

env variables

user…

check…

시작하기

이제 간단하게나마 실제 스크립트 작성을 해보려 한다. "간단하게"라고 표현하기는 했지만, 이 장에서 작성하는 정도면 스크립트의 반은 알게 되는 샘이다.

쉘 스크립트란?

먼저, 쉘 스크립트라는 것이 뭘까? 예전에 DOS의 Batch 파일에 대한 강좌를 쓸 때 사용했던 표현을 빌면, "쉘 스크립트란 라면 봉지에 씌여있는 라면 끓이기 5단계"이다.

라면 봉지에는 다음과 같은 내용이 그림과 함께 씌여져 있다.

  1. 300ml의 물을 펄펄 끓이세요.
  2. 물이 끓으면, 면을 적당히 잘라 넣으세요.
  3. 건더기 스프와 가루스프를 넣으세요.
  4. 3분간 잘 끓이시면 라면이 완성됩니다.
  5. 기호에 따라, 계란이나 치즈를 곁들이세요. (아니면 그냥 드셔요~)

우리는 라면 봉지의 이 스크립트를 읽어서 그 순서에 따라 시키는 동작을 수행함으로써 "맛있는 라면"이라는 결과를 얻게 된다. 쉘 스크립트 역시 이와 비슷하여, 우리가 순서대로 잘 써준 일련의 명령어를 컴퓨터라는 녀석이 읽어서 그 순서에 따라 수행함으로써 우리가 컴퓨터로부터 얻고자 하는 뭔가를 얻게 되는 것이다.

여기서, 몇 가지 간단한 원리가 나오는데, 기본적으로

  1. 쉘 스크립트는 우리가 컴퓨터로부터 뭔가을 얻기 위한 것이다. 그리고 그것은 때로는 (상태정보 등을 얻기 위한) 출력이고, 때로는 어떤 행동 그 자체이기도 하다.
  2. 기본적으로 스크립트는, 위에서 아래로 순차적으로 수행된다. 즉, 스크립트 그 자체가 일의 순서를 정의한 것이며, Procesure에 대한 Communication 수단이 되기도 한다.
  3. 간혹 특정 선행조건을 위한 대기(물이 끓으면), 선택적인 조건이나 분기(기호에 따라 계란이나 치즈) 등이 스크립트를 쓸만하게 만들어 줍니다.

프로그램의 기본 구조

질문 1) 컴퓨터의 구조

질문 2) 프로그램은 ( . . . . . . . )와 ( . . . . . . . )로 구성된다.

위의 질문은 프로그램 또는 Software를 이해하는 기본이 되는 질문이다. 어린 시절, EDPS(Electronic Data Processing System) 또는 "전산학 개론"(이런 영화도 있으면 좋을…까?) 시간에 봤던 "컴퓨터의 기본구조"는 아래와 같은 그림이며, 두 번째 질문의 답은 "알고리즘과 자료구조(Data Structure)"이다.

computer.png

간단한 쉘 스크립트가 되었든, 복잡한 C나 Java 프로그램이 되었든, 기본적인 원리는 똑같다. 바로,

  • 파일이나 단말(Terminal)로부터 적절한 입력을 받아서, (입력)
  • 이렇게 저렇게 계산하거나 가공하고 (명령/연산자/함수)
  • 여러 계산이나 가공 기능 사이를 필요에 따라 왔다 갔다 한 다음, (조건/제어)
  • 최종 결과를 (또는 필요에 따라 중간 결과를) 화면이나 파일에 출력 (출력)

하는 것이다.

이해를 돕고 잘 기억할까 해서 길게 썼는데, 복잡한 얘기는 아니다.

프로그램은 "무엇을 다룰 것인가"와 "어떻게 다룰 것인가"의 조합이다.

간단 실습

엄청 간단한 예제

그냥 단순하게 시킨 일 하나만 하는 스크립트.

#!/bin/bash
 
find /var/log/httpd -type f -mtime +90 -exec rm -f {} \;

find 명령을 써서 원하는 디렉토리(httpd의 로그가 담긴) 안에 위치한, 마지막 수정된 시간이 90일 이상인 파일만 골라 지우는 명령 한 줄을 담은 스크립트로, 반복해서 수행해야 하는 긴 명령행을 간단히 실행하고자 할 경우에 유용할 수도 있다. (이런 경우, 쉘의 alias 기능을 쓸 수도 있지만, 그 방법은 로그인에 종속적인 부분이 있으므로 사용이 불가능한 경우도 있다.)

이 스크립트는 find 명령에 의한 (오류 등의) 출력은 있을지언정, 의도에 의한 출력은 포함하고 있지 않다. 물론, 오류가 있더라도 무시하고 싶다면 아래와 같이 출력을 날려버릴 수도 있다.

#!/bin/bash
 
find /var/log/httpd -type f -mtime +90 -exec rm -f {} \; >/dev/null 2>&1

터미널 출력이 있는 예제

(단순한) 파일 출력이 있는 예제

터미널 입력이 있는 예제

파일 입력이 있는 예제

수치 계산을 포함한 예제

문자열 처리가 포함된 예제

파일 출력이 있는 예제

조건 제어가 들어있는 예제

반복 제어가 들어있는 예제

쉘 스크립트의 실무 활용

설치 시 일괄 환경구성 : 일련의 작업을 순차적 실행

모니터링: 동일 작업의 반복적 수행

자동 장애 극복: 상황에 따른 Call Back/Trigger 처리

흔한 실수, 좋은 버릇

이 스크립트는 왜 작성하고 있는가?

실행 환경과 출력 제어

명령행에서 수동으로 실행하기 위하여

cron에 의해 자동으로 실행하기 위하여

마치며

도움이 필요할 때

Bookmark and Share


따로 명시하지 않는 한에서 이 사이트의 모든 콘텐츠는 다음의 라이선스를 따릅니다: Creative Commons Attribution-NonCommercial 3.0 License