리눅스 시스템을 직접 운영하고 관리하는 시스템 관리자(sysadmin)에게는 업무 효율을 극대화할 수 있는 다양한 도구가 기본적으로 제공됩니다. 이 글은 그러한 도구들을 최대한 활용해 여러분의 업무를 더 편하게 만들어 줄 수 있도록, Bash 셸 스크립트를 활용한 자동화 방법을 다루는 시리즈의 첫 번째 아티클입니다.
이 시리즈에서 다루는 내용
- Bash 셸 스크립트로 자동화할 때의 장점
- C나 C++ 같은 컴파일 언어보다 셸 스크립트가 시스템 관리자에게 더 적합한 이유
- 새로운 스크립트를 위한 요구 사항 정의하기
- 명령줄 인터페이스(CLI) 프로그램에서 간단한 Bash 스크립트 만들기
- 스크립트 실행 사용자 ID(UID)를 활용한 보안 강화
- 논리 비교 도구를 이용한 명령어 및 스크립트의 실행 흐름 제어
- 명령줄 옵션으로 스크립트 기능 제어하기
- 스크립트 내 여러 위치에서 호출 가능한 Bash 함수 만들기
- 코드를 오픈소스로 라이선싱하는 이유와 방법
- 간단한 테스트 계획의 수립과 실행
필자는 이전에 Bash 명령어와 문법, 그리고 명령줄에서 Bash 프로그램을 만드는 방법에 관한 시리즈를 연재한 바 있습니다(본문 마지막 참고 자료 섹션에서 확인하실 수 있습니다). 다만 이번 네 편으로 구성된 시리즈는 단순히 Bash 명령어와 문법을 넘어, 실질적으로 유용한 스크립트 작성 기법에 초점을 맞추고 있습니다.
왜 필자는 셸 스크립트를 사용하는가
The Linux Philosophy for Sysadmins의 9장에서 필자는 다음과 같이 말했습니다.
"시스템 관리자는 생각할 때 가장 생산적이다. 이미 발생한 문제를 어떻게 해결할지, 앞으로 닥칠 문제를 어떻게 예방할지 고민하고, 리눅스 시스템을 어떻게 모니터링해야 미래의 문제를 예고하는 단서를 발견할 수 있을지 생각하며, 자신의 업무를 어떻게 더 효율적으로 만들지, 매일 혹은 일 년에 한 번 수행해야 하는 모든 작업을 어떻게 자동화할지 고민한다.
"그다음으로 생산적인 순간은 겉보기에는 아무것도 하지 않는 것처럼 보이면서도, 머릿속으로 구상한 해결책을 자동화하는 셸 프로그램을 만들 때다. 자동화가 많을수록 실제 문제가 발생했을 때 이를 해결할 시간이 늘어나고, 더 많은 것을 자동화하는 방법을 고민할 여유도 생긴다."
이 첫 번째 글에서는 셸 스크립트가 왜 시스템 관리자에게 중요한 도구인지 살펴보고, 아주 간단한 Bash 스크립트를 만드는 기초를 다룹니다.
왜 자동화해야 하는가?
명령줄에서 길고 복잡한 작업을 마치고 이런 생각을 해 본 적이 있습니까? "다 됐군! 이제 두 번 다시 신경 쓸 일 없겠지." 저도 그런 경험이—무척 많습니다. 결국 깨달은 사실 하나, 컴퓨터에서 하는 거의 모든 작업(내 컴퓨터든 회사든 컨설팅 고객의 시스템이든)은 언젠가 반드시 다시 수행하게 된다는 점입니다.
물론 "다음엔 분명 기억하겠지"라고 생각합니다. 하지만 다음번 작업은 대체로 한참 뒤에 찾아와서, 그전에 해 본 적이 있다는 사실조차 잊어버리고는 합니다. 하물며 어떻게 했는지야 더더욱요. 처음에는 필요한 단계를 종이에 적어두곤 했지만 곧 "내가 뭐 하는 짓이야!"라는 생각이 들었고, 메모장 애플리케이션으로 옮겼습니다. 그러다 어느 날 또다시 "역시 바보 같은 짓을 하고 있네!"라고 깨달았습니다. 어차피 데이터를 컴퓨터에 저장할 거라면, 차라리 셸 스크립트로 만들어 /usr/local/bin이나 ~/bin 같은 표준 위치에 저장하는 편이 낫습니다. 그러면 프로그램 이름만 입력하면 예전에 손으로 하던 모든 작업을 알아서 처리해 주니까요.
필자에게 자동화란, 작업을 다시 수행할 때 그 세부 과정을 기억하거나 재현하지 않아도 된다는 의미입니다. 방법을 떠올리는 데도 시간이 들고, 긴 명령어를 일일이 입력하는 데도 시간이 듭니다. 특히 입력해야 할 명령이 많고 길다면 상당한 시간 낭비가 됩니다. 셸 스크립트로 작업을 자동화하면 반복 작업에 필요한 타이핑량이 크게 줄어듭니다.
셸 스크립트
셸 프로그램, 즉 스크립트를 작성하는 것은 시간을 가장 효과적으로 활용하는 전략입니다. 한 번 셸 프로그램을 작성해 두면 필요한 만큼 몇 번이고 다시 실행할 수 있습니다. 또한 리눅스 릴리스가 바뀌거나 새로운 하드웨어·소프트웨어를 설치할 때, 스크립트로 달성하고자 하는 목표가 달라질 때, 새 기능을 추가하거나 불필요해진 기능을 제거할 때, 드물지 않게 발생하는 버그를 수정할 때도 스크립트를 지속적으로 갱신할 수 있습니다. 이런 변경 작업은 어떤 코드든 거치는 유지보수 주기의 일부입니다.
터미널 세션에서 키보드로 입력하고 실행하는 모든 셸 명령 작업은 자동화할 수 있고, 자동화해야 합니다. 시스템 관리자는 요청받은 작업이든 스스로 필요하다고 판단한 작업이든 무엇이든 자동화해야 합니다. 많은 경우, 자동화를 먼저 해두면 첫 시행부터 오히려 시간이 절약되기도 합니다.
Bash 스크립트 하나에는 몇 개의 명령어에서 수천 줄까지 담을 수 있습니다. 필자는 명령어 한두 개짜리 Bash 스크립트도 작성해 봤고, 2,700줄이 넘고 그 절반 이상이 주석인 스크립트도 작성해 봤습니다.
시작하기
간단한 셸 스크립트 예제와 그 작성 방법을 소개합니다. 필자가 예전에 연재한 Bash 명령줄 프로그래밍 시리즈에서도 그랬듯, 모든 프로그래밍 교재에 등장하는 그 예제, "Hello world"부터 시작하겠습니다. 명령줄에서 실행하면 다음과 같습니다:
[student@testvm1 ~]$ echo "Hello world"
Hello world
정의상 프로그램 또는 셸 스크립트란 컴퓨터가 실행할 일련의 명령어 집합입니다. 하지만 이를 매번 명령줄에 직접 입력하는 건 상당히 번거롭습니다. 프로그램이 길고 복잡할수록 더욱 그렇습니다. 이를 파일로 저장해 단 한 번의 명령으로 실행할 수 있게 하면 시간이 절약되고 오류가 끼어들 가능성도 줄어듭니다.
다음 예제들은 루트(root)가 아닌 일반 사용자로, 테스트 시스템이나 가상머신(VM)에서 시도해 보길 권합니다. 예제 자체는 무해하지만 실수는 언제든 일어날 수 있으므로 안전을 기하는 것이 현명합니다.
첫 번째 작업은 프로그램을 담을 파일을 생성하는 것입니다. touch 명령으로 빈 파일 hello를 만들고, 실행 권한을 부여합니다:
[student@testvm1 ~]$ touch hello
[student@testvm1 ~]$ chmod 774 hello
이제 선호하는 편집기로 다음 한 줄을 파일에 추가합니다:
echo "Hello world"
파일을 저장하고 명령줄에서 실행해 봅니다. 이 시리즈의 스크립트를 실행할 별도의 셸 세션을 열어두는 것도 좋습니다:
[student@testvm1 ~]$ ./hello
Hello world!
이것이 여러분이 만들 수 있는 가장 단순한 Bash 프로그램입니다. 파일 안의 단 한 줄 문장이죠. 이 연습의 목적상 스크립트의 기능 자체는 중요하지 않습니다. 이 단순한 문장을 중심으로 전체 셸 스크립트 구조를 만들어 갑니다. 기능 로직에 얽매이지 않고 기본 프로그램 구조, 즉 다른 프로그램의 밑바탕이 될 템플릿을 아주 간단한 방식으로 만들고 테스트하는 데 집중할 수 있습니다.
Shebang
이 단일 문장은 Bash 또는 스크립트에 사용된 명령어와 호환되는 셸을 사용하는 한 잘 동작합니다. 스크립트에 셸이 명시되어 있지 않으면 기본 셸(default shell)이 스크립트 명령을 실행합니다.
다음 과제는, 기본 셸이 무엇이든 이 스크립트가 반드시 Bash로 실행되도록 보장하는 것입니다. 이를 위해 사용하는 것이 바로 shebang 라인입니다. Shebang은 스크립트 실행에 사용할 셸을 명시적으로 지정하는 #! 문자를 부르는, 다소 덕후스러운 표현입니다. 여기서는 Bash를 지정하지만 다른 어떤 셸이든 지정할 수 있습니다. 단, 지정된 셸이 설치되어 있지 않으면 스크립트는 실행되지 않습니다.
shebang 라인을 스크립트의 첫 줄에 추가하면 다음과 같습니다:
#!/usr/bin/bash
echo "Hello world!"
스크립트를 다시 실행해 보세요. 결과에는 차이가 없을 것입니다. ksh, csh, tcsh, zsh 등 다른 셸이 설치되어 있다면 해당 셸을 시작한 뒤 스크립트를 다시 실행해 보세요.
셸 스크립트 vs. 컴파일 프로그램
자동화를 위한 프로그램을 작성할 때, 시스템 관리자는 항상 셸 스크립트를 사용해야 합니다. 셸 스크립트는 ASCII 텍스트 형식으로 저장되기 때문에 사람도 컴퓨터처럼 손쉽게 열람하고 수정할 수 있습니다. 셸 프로그램을 들여다보면 무엇을 하는지 정확히 파악할 수 있고, 문법이나 로직에 명백한 오류가 있는지도 확인할 수 있습니다. 이것이야말로 '열려 있다(open)'는 것의 강력한 실례입니다.
일부 개발자들은 셸 스크립트를 '진짜' 프로그래밍에 못 미치는 것으로 치부합니다. 셸 스크립트와 그 작성자들을 하찮게 여기는 이런 시각은, 소스 코드를 컴파일해 실행 코드를 만들어내는 언어만이 유일한 '진짜' 프로그래밍 언어라는 생각에 기반한 것 같습니다. 하지만 경험상 이는 명백히 사실이 아닙니다.
필자는 BASIC, C, C++, Pascal, Perl, Tcl/Expect, REXX(및 Object REXX 등 변종들), Korn·csh·Bash를 포함한 다양한 셸 언어, 심지어 일부 어셈블리 언어까지 폭넓게 사용해 왔습니다. 지금까지 탄생한 모든 컴퓨터 언어의 목적은 단 하나였습니다. 사람이 컴퓨터에게 할 일을 지시할 수 있게 하는 것. 어떤 언어를 선택하든, 프로그램을 작성한다는 것은 특정 작업을 특정 순서로 수행하도록 컴퓨터에 명령을 내리는 행위입니다.
스크립트는 컴파일 언어보다 훨씬 빠르게 작성하고 테스트할 수 있습니다. 프로그램은 대체로 환경이나, 혹은 '뾰족머리 상사'가 부과하는 시간 제약 안에 빠르게 완성되어야 합니다. 시스템 관리자가 작성하는 스크립트 대부분은 문제를 해결하거나, 문제의 후유증을 정리하거나, 컴파일 프로그램이 작성·테스트되기 한참 전에 가동돼야 하는 프로그램을 제공하기 위한 것입니다.
프로그램을 빠르게 작성하려면 셸 프로그래밍이 필수입니다. 고객—그 고객이 자신이든 남이든—의 요구에 신속히 대응할 수 있기 때문입니다. 로직에 문제가 있거나 코드에 버그가 있어도 즉시 수정하고 재테스트할 수 있습니다. 초기 요구 사항에 결함이 있거나 미완성이어도, 셸 스크립트는 새 요구 사항을 충족하도록 매우 빠르게 수정할 수 있습니다. 일반적으로 시스템 관리자 업무에서는 개발 속도가, 프로그램 실행 속도를 최대화하거나 RAM 같은 시스템 자원 사용을 최소화하는 것보다 우선합니다.
시스템 관리자가 하는 일 대부분은 실제 실행보다 '방법을 알아내는 데' 더 오래 걸립니다. 따라서 모든 작업에 셸 스크립트를 만드는 게 비효율적으로 보일 수도 있습니다. 스크립트를 작성하고, 재현 가능한 결과를 내는 도구로 다듬고, 필요할 때마다 쓸 수 있게 만드는 데는 어느 정도 시간이 들니까요. 하지만 시간 절약은 스크립트를 실행할 때마다, 다시 방법을 고민하지 않아도 되는 순간마다 돌아옵니다.
마치며
이 글에서 셸 스크립트 작성을 아주 멀리 진행하지는 못했지만, 아주 작은 하나는 만들어 봤습니다. 또한 셸 스크립트를 작성하는 이유와, 시스템 관리자에게 있어 셸 스크립트가 컴파일 프로그램보다 왜 가장 효율적인 선택인지도 살펴봤습니다.
다음 글에서는 다른 Bash 스크립트의 출발점으로 활용할 수 있는 Bash 스크립트 템플릿을 만들기 시작합니다. 이 템플릿에는 최종적으로 도움말(Help) 기능, GNU 라이선스 문구, 여러 간단한 함수, 그리고 옵션 처리 로직과 함께 이 템플릿 기반 스크립트들에 필요할 수 있는 추가 요소들이 담기게 됩니다.
참고 자료
- Bash로 프로그래밍하기: 문법과 도구
- Bash로 프로그래밍하기: 논리 연산자와 셸 확장
- Bash로 프로그래밍하기: 반복문
이 시리즈는 David Both의 3부작 리눅스 독학 강좌 'Using and Administering Linux—Zero to SysAdmin' 2권 10장의 내용을 일부 기반으로 합니다.