리눅스 셸에 로그인하면 특정한 작업 환경을 물려받게 됩니다. 셸에서 말하는 환경(environment)이란, 명령어가 의도한 대로 동작할 수 있도록 여러 변수들이 이미 설정되어 있는 상태를 의미합니다. 예를 들어 PATH 환경 변수는 셸이 명령어를 찾을 위치를 정의합니다. 이 변수가 없다면 Bash에서 시도하는 거의 모든 작업이 command not found 오류와 함께 실패하게 됩니다. 평소에는 잘 눈에 띄지 않지만, 환경은 시스템 운영에 필수적인 요소입니다.
셸 환경에 영향을 주는 방법은 다양합니다. ~/.bashrc나 ~/.profile 같은 설정 파일을 수정할 수도 있고, 부팅 시 서비스를 실행하도록 구성할 수도 있으며, 자신만의 사용자 지정 명령을 만들거나 Bash 함수를 직접 스크립트로 작성할 수도 있습니다.
source로 환경에 요소 추가하기
Bash(및 일부 다른 셸)에는 source라는 내장 명령어가 있습니다. 여기서 혼동하기 쉬운 점이 있는데, source는 마침표 하나(.)로 이루어진 명령어와 완전히 동일한 기능을 수행하며, Tcl 명령어의 source(man source를 입력했을 때 화면에 나타날 수 있는)와는 전혀 다른 것입니다. 실제로 내장된 source 명령은 PATH에 아예 포함되어 있지 않습니다. 이는 Bash에 기본 탑재된 명령어로, 자세한 정보가 필요하면 help source를 입력하면 확인할 수 있습니다.
. 명령어는 POSIX 규격을 준수합니다. 반면 source 명령어는 POSIX에 정의되어 있지 않지만, . 명령어와 상호 호환됩니다.
Bash의 help 설명에 따르면, source 명령은 현재 셸에서 파일을 실행합니다. 여기서 "현재 셸에서"라는 구절이 매우 중요합니다. 별도의 하위 셸(sub-shell)을 생성하지 않기 때문입니다. 즉, source로 실행하는 모든 내용은 현재 환경 안에서 동작하며, 그 환경에 직접적인 영향을 미칩니다.
source가 환경에 어떤 영향을 주는지 살펴보기 전에, 간단한 테스트 파일로 코드가 예상대로 실행되는지 확인해 보겠습니다. 먼저 아래와 같은 간단한 Bash 스크립트를 작성해 hello.sh라는 이름으로 저장합니다:
#!/usr/bin/env bash
echo "hello world"
source를 사용하면 실행 권한(executable bit)을 부여하지 않고도 이 스크립트를 실행할 수 있습니다:
$ source hello.sh
hello world
내장된 . 명령어를 사용해도 동일한 결과를 얻을 수 있습니다:
$ . hello.sh
hello world
source와 . 명령어 모두 테스트 파일의 내용을 성공적으로 실행했습니다.
변수 설정과 함수 가져오기
source를 활용하면 파일을 셸 환경으로 "가져올(import)" 수 있습니다. C나 C++에서 include 키워드로 라이브러리를 참조하거나, Python에서 import 키워드로 모듈을 불러오는 것과 비슷한 개념입니다. 이것이 source의 가장 흔한 용도 중 하나이며, 실제로 많은 .bashrc 파일에는 .bash_aliases 파일을 source하는 구문이 기본적으로 포함되어 있어, 로그인 시 사용자가 정의한 커스텀 별칭(alias)들이 자동으로 환경에 반영됩니다.
Bash 함수를 가져오는 예제를 살펴보겠습니다. 먼저 myfunctions라는 파일에 함수를 작성합니다. 이 함수는 공인(public) IP 주소와 로컬 IP 주소를 출력합니다:
function myip() {
curl https://icanhazip.com
ip addr | grep inet$IP | \
cut -d"/" -f 1 | \
grep -v 127\.0 | \
grep -v \:\:1 | \
awk '{$1=$1};1'
}
작성한 함수를 셸로 가져옵니다:
$ source myfunctions
그리고 새 함수를 테스트해 봅니다:
$ myip
93.184.216.34
inet 192.168.0.23
inet6 fbd4:e85f:49c:2121:ce12:ef79:0e77:59d1
inet 10.8.42.38
source의 파일 검색 방식
Bash에서 source를 사용하면 먼저 현재 디렉토리에서 참조한 파일을 찾습니다. 다만 이 동작은 모든 셸에서 동일하게 적용되는 것은 아니므로, 다른 셸을 사용한다면 해당 셸의 문서를 확인하는 것이 좋습니다.
Bash가 실행할 파일을 현재 디렉토리에서 찾지 못하면, 이번에는 PATH를 검색합니다. 역시 이것도 모든 셸의 공통 동작은 아니므로 참고하시기 바랍니다.
이 두 가지 편의 기능은 생각보다 강력합니다. 공통으로 사용하는 함수들을 드라이브의 한 곳에 중앙 집중식으로 저장하고, 셸 환경을 마치 통합 개발 환경(IDE)처럼 다룰 수 있게 해주기 때문입니다. 함수가 어디에 저장되어 있는지 일일이 걱정할 필요가 없습니다. /usr/include의 로컬 버전에 해당하는 위치에 함수들이 있다는 것만 알면, 어디에서든 source를 실행할 때 Bash가 알아서 찾아냅니다.
예를 들어, 공통 함수를 보관할 ~/.local/include라는 디렉토리를 만들고, 아래 코드 블록을 .bashrc 파일에 추가할 수 있습니다:
for i in $HOME/.local/include/*;
do source $i
done
이렇게 하면 ~/.local/include 안에 있는 커스텀 함수 파일들이 모두 셸 환경으로 자동 "가져와집니다".
참고로, source 또는 . 명령어 사용 시 현재 디렉토리와 PATH를 모두 검색하는 셸은 Bash가 유일합니다.
오픈 소스 프로젝트에서 source 활용하기
source나 . 명령어로 파일을 실행하는 방식은, 환경을 손쉽게 변경하면서도 수정 사항을 모듈 단위로 깔끔하게 유지할 수 있는 훌륭한 방법입니다. 다음에 .bashrc 파일에 긴 코드 블록을 복사해 붙여넣으려 할 때는, 관련된 함수나 별칭 그룹을 별도의 전용 파일로 분리해두고 source로 불러오는 방식을 고려해 보세요. 관리가 훨씬 수월해질 것입니다.