프로그램의 설정을 코드와 분리해 관리하는 것은 매우 중요합니다. 이렇게 하면 프로그래머가 아닌 사용자도 코드를 수정하지 않고 설정을 변경할 수 있기 때문입니다. 컴파일된 바이너리 실행 파일의 경우, 소스 파일에 접근할 수 있다 해도(오픈소스라면 가능) 프로그래밍 지식이 없다면 수정이 사실상 불가능합니다. 그런 능력을 갖춘 사람은 많지 않으며, 대부분 배우고 싶어하지도 않습니다.
반면 Bash 같은 셸 언어는 스크립트가 바이너리로 컴파일되지 않기 때문에 정의상 소스 코드에 접근할 수 있습니다. 하지만 그렇다고 해서 비전문가가 셸 스크립트를 직접 열어 수정하는 것은 좋은 방법이 아닙니다. 숙련된 개발자나 시스템 관리자조차 실수로 오류를 일으키거나 더 큰 문제를 만들 수 있습니다.
따라서 설정 항목을 관리하기 쉬운 텍스트 파일에 분리해 두면, 비전공자도 코드를 건드릴 위험 없이 설정값만 안전하게 편집할 수 있습니다. 많은 개발자가 컴파일 언어로 작성한 프로그램에서도 이런 방식을 사용하는데, 사용자가 반드시 개발자일 것이라고 기대하지 않기 때문입니다. 같은 이유로 인터프리터 방식의 셸 언어에서도 설정을 분리하는 것이 합리적입니다.
일반적인 방식
다른 많은 언어와 마찬가지로, Bash 프로그램에서도 ASCII 텍스트 형식의 설정 파일을 읽고 파싱하여 변수 이름을 확인하고 값을 할당하는 코드를 직접 작성할 수 있습니다. 예를 들어 설정 파일은 다음과 같은 형태일 수 있습니다.
var1=LinuxGeek46
var2=Opensource.com
프로그램은 이 파일을 읽어 각 줄을 파싱하고, 해당 변수에 값을 할당하게 됩니다.
소싱(Sourcing): 훨씬 간단한 방법
Bash에는 소싱(sourcing)이라는 훨씬 쉬운 파싱 및 변수 설정 방법이 있습니다. 실행 중인 셸 프로그램에서 외부 파일을 소스(source)하면, 그 파일의 내용 전체를 셸 프로그램에 그대로 포함시킬 수 있습니다. 어떤 의미에서는 런타임에 라이브러리 파일을 포함시키는 컴파일 언어의 include 문과 매우 유사합니다. 이러한 파일에는 변수 할당을 포함해 모든 종류의 Bash 코드를 담을 수 있습니다.
역시 설명보다 직접 보여주는 것이 이해하기 쉽습니다.
먼저 ~/bin 디렉터리를 생성하고(아직 없다면), 현재 작업 디렉터리(PWD)로 이동합니다. 리눅스 파일시스템 계층 표준(FHS)은 사용자가 실행 파일을 저장하기에 적합한 위치로 ~/bin을 정의하고 있습니다.
이 디렉터리에 새 파일을 만들고 이름을 main으로 지정한 뒤 실행 권한을 부여합니다.
[dboth@david bin]$ touch main
[dboth@david bin]$ chmod +x main
[dboth@david bin]$
이 실행 파일에 다음 내용을 추가합니다.
#!/bin/bash
Name="LinuxGeek"
echo $Name
그리고 이 Bash 프로그램을 실행해 봅니다.
[dboth@david bin]$ ./main
LinuxGeek
[dboth@david bin]$
이제 새 파일 ~/bin/data를 생성합니다. 이 파일은 실행 권한이 필요하지 않습니다. 다음 내용을 추가합니다.
# Sourced code and variables
echo "This is the sourced code from the data file."
FirstName="David"
LastName="Both"
main 프로그램에 세 줄을 추가해 다음과 같이 만듭니다.
#!/bin/bash
Name="LinuxGeek"
echo $Name
source ~/bin/data
echo "First name: $FirstName"
echo "LastName: $LastName"
프로그램을 다시 실행하면 다음과 같은 결과를 볼 수 있습니다.
[dboth@david bin]$ ./main
LinuxGeek
This is the sourced code from the data file.
First name: David
LastName: Both
[dboth@david bin]$
소싱에 대해 알아두면 정말 유용한 팁이 하나 더 있습니다. source 명령 대신 마침표(.) 하나를 단축형으로 사용할 수 있습니다. main 파일에서 source를 .으로 바꿔 보겠습니다.
#!/bin/bash
Name="LinuxGeek"
echo $Name
. ~/bin/data
echo "First name: $FirstName"
echo "LastName: $LastName"
프로그램을 다시 실행하면 이전 실행 결과와 정확히 동일한 출력을 확인할 수 있습니다.
Bash 시작 시의 소싱
Bash를 사용하는 모든 리눅스 호스트—사실상 모든 배포판이 Bash를 기본 셸로 사용하므로 거의 전부입니다—에는 소싱의 훌륭한 내장 예시들이 포함되어 있습니다.
Bash 셸이 시작될 때마다 사용 가능한 환경이 되도록 구성 과정이 필요합니다. Bash 환경을 설정하는 데 사용되는 주요 파일 다섯 개와 디렉터리 하나가 있으며, 각각의 주요 역할은 다음과 같습니다.
/etc/profile: 시스템 전체 환경 및 시작 프로그램/etc/bashrc: 시스템 전체 함수 및 앨리어스(alias)/etc/profile.d/:vim,mc같은 다양한 명령줄 도구를 설정하는 시스템 전체 스크립트와, 시스템 관리자가 만든 사용자 정의 설정 스크립트가 담긴 디렉터리~/.bash_profile: 사용자별 환경 및 시작 프로그램~/.bashrc: 사용자별 앨리어스 및 함수~/.bash_logout: 로그아웃 시 실행할 사용자별 명령
이 파일들을 통해 실행 순서를 추적해 보고, 로그인 셸 초기화와 비로그인(non-login) 셸 초기화가 각각 어떤 순서로 진행되는지 파악해 보세요. 저는 제 리눅스 교육 시리즈 1권 Using and administering Linux: Zero to sysadmin의 17장에서 이 주기를 자세히 다룬 적이 있습니다.
힌트를 하나 드리자면, 모든 것은 ~/.bashrc 스크립트에서 시작됩니다.
마무리
이 글에서는 소싱을 활용해 코드와 변수 할당을 Bash 프로그램으로 가져오는 방법을 살펴보았습니다. 설정 파일에서 변수를 파싱하는 이 방식은 빠르고, 간단하며, 유연합니다. Bash 코드와 변수 할당을 분리함으로써 프로그래머가 아닌 사용자도 안전하게 변수값을 설정할 수 있는 방법을 제공합니다.