Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

Bash 스크립트 작성 마스터하기: 변수, 상수, 그리고 무결성 검사

이 시리즈의 첫 번째 글에서는 아주 짧은 한 줄짜리 Bash 스크립트를 직접 만들어 보고, 셸 스크립트를 작성해야 하는 이유를 살펴보았습니다. 두 번째 글에서는 다른 Bash 프로그램의 출발점으로 활용할 수 있는 비교적 간단한 템플릿을 만들기 시작했고, 세 번째 글에서는 간단한 Help 함수를 만들어 사용하는 방법과 -h 같은 명령줄 옵션을 처리하는 방법을 배웠습니다.

시리즈의 네 번째이자 마지막 글에서는 변수와 변수 초기화 방법, 그리고 프로그램이 올바른 조건에서 실행되도록 돕는 간단한 무결성 검사(sanity check) 방법을 다룹니다. 이 시리즈의 목표는 향후 Bash 프로그래밍 프로젝트의 템플릿으로 활용할 수 있는 실제 동작하는 코드를 만드는 것임을 기억하세요. 공통 요소들이 이미 갖춰진 템플릿 덕분에 새로운 프로그래밍 프로젝트를 쉽게 시작할 수 있다는 것이 핵심입니다.

변수

Bash 셸은 모든 프로그래밍 언어와 마찬가지로 변수를 다룰 수 있습니다. 변수란 어떤 값을 담고 있는 메모리의 특정 위치를 가리키는 기호적인 이름입니다. 변수의 값은 변경 가능합니다. 즉, '가변적'인 것이죠. 변수 사용에 익숙하지 않다면, 더 읽어 나가기 전에 제 이전 글인 Bash로 프로그래밍하는 방법: 문법과 도구를 먼저 참고하시기 바랍니다.

다 읽으셨나요? 좋습니다! 이제 변수를 사용할 때의 몇 가지 모범 사례를 살펴보겠습니다.

저는 항상 스크립트에서 사용하는 모든 변수에 초기값을 설정합니다. 이 부분은 템플릿 스크립트에서 프로시저(함수) 바로 뒤, 즉 옵션 처리 코드 이전의 메인 프로그램 본문 시작 부분에서 찾을 수 있습니다. 각 변수를 적절한 값으로 초기화하면, 초기화되지 않은 변수로 인해 비교 연산이나 산술 연산에서 발생할 수 있는 오류를 예방할 수 있습니다. 또한 변수 목록을 한곳에 모아 두면 스크립트에 어떤 변수들이 있어야 하는지, 그리고 그 초기값은 무엇인지 한눈에 파악할 수 있습니다.

여러분의 작은 스크립트에는 현재 $option이라는 단 하나의 변수만 있습니다. 다음과 같은 줄을 삽입하여 설정해 보세요.

################################################################################
################################################################################
# Main program #
################################################################################
################################################################################
# Initialize variables
option=""
################################################################################
# Process the input options. Add options as needed. #
################################################################################

변경 후에는 모든 것이 정상적으로 동작하고, 이번 수정으로 인해 아무것도 깨지지 않았는지 반드시 테스트하세요.

상수

상수 역시 일종의 변수입니다. 적어도 그렇게 취급해야 합니다. 명령줄 인터페이스(CLI) 프로그램에서는 하드코딩된 값 대신 최대한 변수를 사용하세요. 특정 값(디렉터리 이름, 파일 이름, 문자열 등)을 딱 한 번만 사용할 것 같더라도, 변수로 만들어 하드코딩된 이름 대신 사용하는 것이 좋습니다.

예를 들어, 프로그램 본문에서 출력되는 메시지는 문자열 리터럴인 echo "Hello world!"입니다. 이를 변수로 바꿔 보겠습니다. 먼저 변수 초기화 섹션에 다음 문장을 추가합니다.

Msg="Hello world!"

그리고 프로그램의 마지막 줄을 다음과 같이 변경합니다.

echo "$Msg"

그런 다음 결과를 테스트해 보세요.

무결성 검사

무결성 검사(sanity check)란 프로그램이 올바르게 동작하기 위해 충족되어야 하는 조건을 확인하는 테스트입니다. 예를 들어 프로그램이 root 사용자 권한으로 실행되어야 한다거나, 특정 배포판과 릴리스 환경에서 실행되어야 하는 경우 등이 있습니다. 여러분의 간단한 프로그램 템플릿에 root 사용자 여부를 확인하는 검사를 추가해 보겠습니다.

프로그램은 실행시킨 사용자의 권한으로 동작하기 때문에, root 사용자로 프로그램이 실행 중인지 확인하는 것은 매우 간단합니다.

id 명령을 사용하면 프로그램이 실행되고 있는 숫자형 사용자 ID(UID)를 알아낼 수 있습니다. 옵션 없이 실행하면 여러 정보를 함께 출력합니다.

[student@testvm1 ~]$ id
uid=1001(student) gid=1001(student) groups=1001(student),5000(dev)

-u 옵션을 사용하면 사용자의 UID만 반환되므로 Bash 프로그램에서 손쉽게 활용할 수 있습니다.

[student@testvm1 ~]$ id -u
1001
[student@testvm1 ~]$

프로그램에 다음 함수를 추가합니다. 저는 Help 프로시저 뒤에 추가했지만, 프로시저 섹션 어느 곳에 배치해도 무방합니다. 로직은 간단합니다. UID가 0이 아니면(root 사용자의 UID는 항상 0입니다) 프로그램을 종료하는 것입니다.

################################################################################
# Check for root. #
################################################################################
CheckRoot()
{
if [ `id -u` != 0 ]
then
echo "ERROR: You must be root user to run this program"
exit
fi
}

이제 CheckRoot 프로시저 호출을 변수 초기화 코드 바로 앞에 추가합니다. 먼저 student 사용자로 프로그램을 실행하여 테스트해 보세요.

[student@testvm1 ~]$ ./hello 
ERROR: You must be root user to run this program
[student@testvm1 ~]$

그다음 root 사용자로 실행해 봅니다.

[root@testvm1 student]# ./hello 
Hello world!
[root@testvm1 student]#

이러한 무결성 검사가 항상 필요하지 않을 수 있으므로, CheckRoot 호출 부분은 주석 처리하되 코드 전체는 템플릿에 그대로 남겨 두세요. 이렇게 해 두면 향후 프로그램에서 이 코드를 사용할 때 주석만 해제하면 됩니다.

완성된 코드

위에서 설명한 변경 사항을 모두 적용하면 코드는 다음과 같습니다.

#!/usr/bin/bash
################################################################################
# scriptTemplate #
# #
# Use this template as the beginning of a new program. Place a short #
# description of the script here. #
# #
# Change History #
# 11/11/2019 David Both Original code. This is a template for creating #
# new Bash shell scripts. #
# Add new history entries as needed. #
# #
# #
################################################################################
################################################################################
################################################################################
# #
# Copyright (C) 2007, 2019 David Both #
# LinuxGeek46@both.org #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# #
################################################################################
################################################################################
################################################################################

################################################################################
# Help #
################################################################################
Help()
{
# Display Help
echo "Add description of the script functions here."
echo
echo "Syntax: scriptTemplate [-g|h|v|V]"
echo "options:"
echo "g Print the GPL license notification."
echo "h Print this Help."
echo "v Verbose mode."
echo "V Print software version and exit."
echo
}

################################################################################
# Check for root. #
################################################################################
CheckRoot()
{
# If we are not running as root we exit the program
if [ `id -u` != 0 ]
then
echo "ERROR: You must be root user to run this program"
exit
fi
}

################################################################################
################################################################################
# Main program #
################################################################################
################################################################################

################################################################################
# Sanity checks #
################################################################################
# Are we rnning as root?
# CheckRoot

# Initialize variables
option=""
Msg="Hello world!"
################################################################################
# Process the input options. Add options as needed. #
################################################################################
# Get the options
while getopts ":h" option; do
case $option in
h) # display Help
Help
exit;;
\?) # incorrect option
echo "Error: Invalid option"
exit;;
esac
done

echo "$Msg"

마무리 연습 문제

코드의 Help 함수가 실제 코드에는 없는 기능들을 안내하고 있다는 것을 눈치채셨을 겁니다. 마지막 연습 과제로, 해당 기능들을 여러분이 만든 코드 템플릿에 추가하는 방법을 스스로 찾아 구현해 보세요.

요약

이번 글에서는 프로그램이 root 권한으로 실행 중인지 확인하는 무결성 검사를 수행하는 함수 두 개를 만들었습니다. 프로그램이 점점 복잡해지면서 테스트의 중요성도 커지고 있으며, 완전한 테스트를 위해서는 더 많은 테스트 경로가 필요합니다.

이 시리즈에서는 아주 최소한의 Bash 프로그램을 살펴보고, 이를 조금씩 발전시켜 나가는 방법을 배웠습니다. 그 결과물은 더 유용한 Bash 스크립트의 출발점이 될 수 있는 간단한 템플릿이며, 새로운 스크립트를 쉽게 시작할 수 있게 해주는 유용한 요소들을 포함하고 있습니다.

이제 감이 잡히셨을 겁니다. 컴파일된 프로그램도 필요하고 매우 중요한 역할을 합니다. 하지만 시스템 관리자에게는 언제나 더 나은 방법이 있습니다. 업무 자동화가 필요할 때는 항상 셸 스크립트를 사용하세요. 셸 스크립트는 열려(open) 있어서 내용과 목적을 파악할 수 있고, 서로 다른 요구 사항에 맞게 손쉽게 수정할 수 있습니다. 필자는 시스템 관리자로서 셸 스크립트로 해결할 수 없는 업무를 경험해 본 적이 없습니다.

지금까지 이 시리즈에서 만든 것은 시작에 불과합니다. 더 많은 Bash 프로그램을 작성하다 보면 자주 사용하게 되는 코드 조각들을 발견하게 될 것이며, 이런 것들이 프로그램 템플릿에 포함되어야 할 것입니다.

참고 자료

  • Bash로 프로그래밍하는 방법: 문법과 도구
  • Bash로 프로그래밍하는 방법: 논리 연산자와 셸 확장
  • Bash로 프로그래밍하는 방법: 반복문

이 시리즈는 David Both의 3부작 Linux 자율 학습 과정인 『Using and Administering Linux—Zero to SysAdmin』 2권 10장의 내용을 일부 기반으로 작성되었습니다.