함수 라이브러리와 source
로그 출력, 색상 메시지, 사용자 확인 프롬프트. 스크립트마다 비슷한 함수를 새로 작성하는 것은 낭비입니다. 한 파일에 모아두고 필요할 때 불러다 쓰면 됩니다. Python의 import, JavaScript의 require처럼, Bash에도 외부 파일을 불러오는 방법이 있습니다.
source 명령어
source 명령어(또는 .으로 줄여 쓸 수 있음)는 지정한 파일을 현재 쉘 환경에서 실행합니다. 파일 안에 정의된 함수와 변수가 현재 쉘로 가져와집니다.
source 파일경로# 또는. 파일경로
두 가지는 동작이 같습니다. source가 더 명확하게 읽히지만, .은 POSIX 표준이라 어떤 쉘에서도 동작합니다.
# utils.sh 라이브러리 로드source ./utils.sh# 또는. ./utils.sh
source로 불러온 파일의 함수는 마치 현재 스크립트에 직접 쓴 것처럼 사용할 수 있습니다. 단, 불러오기 전에 함수를 호출하면 오류가 납니다.
라이브러리 경로 패턴
라이브러리 파일의 경로를 하드코딩하면 스크립트를 다른 위치에서 실행할 때 경로가 맞지 않는 문제가 생깁니다. 스크립트 자신의 위치를 기준으로 라이브러리 경로를 찾는 패턴을 씁니다.
# 스크립트 파일이 있는 디렉토리를 기준으로 라이브러리 로드SCRIPT_DIR="$(dirname "$(realpath "$0")")"source "${SCRIPT_DIR}/lib_utils.sh"
$0은 현재 스크립트 경로, dirname은 디렉토리 부분 추출, realpath는 심볼릭 링크를 따라 실제 경로로 변환합니다. 어떤 디렉토리에서 스크립트를 실행해도 항상 같은 위치의 라이브러리를 찾습니다.
함수 라이브러리 파일 작성
실제 프로젝트에서 자주 쓰는 유틸리티 함수 모음을 만들어봅니다. 파일명은 관례적으로 lib_*.sh 또는 utils.sh로 짓습니다.
#!/bin/bash# 새 파일: lib_utils.sh# lib_utils.sh — 공통 유틸리티 함수 라이브러리# 색상 코드 상수RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'BLUE='\033[0;34m'NC='\033[0m' # No Color (초기화)# 로그 함수들log_info() { local message="$1" echo -e "${BLUE}[INFO]${NC} $(date '+%H:%M:%S') $message"}log_warn() { local message="$1" echo -e "${YELLOW}[WARN]${NC} $(date '+%H:%M:%S') $message" >&2}log_error() { local message="$1" echo -e "${RED}[ERROR]${NC} $(date '+%H:%M:%S') $message" >&2}# 색상 출력 함수들print_green() { echo -e "${GREEN}$1${NC}"}print_red() { echo -e "${RED}$1${NC}"}print_yellow() { echo -e "${YELLOW}$1${NC}"}# 사용자 확인 프롬프트# 사용법: confirm "계속하시겠습니까" && do_somethingconfirm() { local prompt="${1:-계속하시겠습니까?}" local answer read -rp "${prompt} [y/N] " answer case "$answer" in [yY] | [yY][eE][sS]) return 0 # 승인 ;; *) return 1 # 거부 ;; esac}# 구분선 출력print_separator() { echo "=================================================="}# 섹션 헤더 출력print_header() { local title="$1" print_separator echo " ${title}" print_separator}
이 파일 자체는 실행할 목적이 아닙니다. 다른 스크립트에서 불러다 쓰는 것이 목적이므로 실행 가능 상태로 만들지 않아도 됩니다. 단, 첫 줄의 shebang은 에디터의 문법 강조와 쉘 호환성 힌트를 위해 넣어두는 것이 좋습니다.
실습: 라이브러리를 활용한 시스템 정보 출력 스크립트
위에서 만든 lib_utils.sh를 사용하는 스크립트입니다.
#!/bin/bash# 새 파일: system_info.sh# system_info.sh — lib_utils.sh를 활용한 시스템 정보 출력# 라이브러리 로드 (스크립트 위치 기준)SCRIPT_DIR="$(dirname "$(realpath "$0")")"source "${SCRIPT_DIR}/lib_utils.sh"# 시스템 정보 수집 함수get_cpu_info() { local cpu cpu=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs) echo "$cpu"}get_memory_info() { local total used total=$(free -m | awk '/^Mem:/ {print $2}') used=$(free -m | awk '/^Mem:/ {print $3}') echo "사용 중: ${used}MB / 전체: ${total}MB"}get_disk_info() { df -h / | awk 'NR==2 {printf "사용 중: %s / 전체: %s (%s)", $3, $2, $5}'}# --- 메인 실행 ---print_header "시스템 정보 보고서"echo ""log_info "정보 수집 시작..."echo ""print_green "호스트명: $(hostname)"print_green "사용자: $(whoami)"print_green "운영체제: $(lsb_release -d 2>/dev/null | cut -f2 || uname -o)"print_green "커널 버전: $(uname -r)"print_green "가동 시간: $(uptime -p 2>/dev/null || uptime)"echo ""print_green "CPU: $(get_cpu_info)"print_green "메모리: $(get_memory_info)"print_green "디스크(/): $(get_disk_info)"echo ""log_info "정보 수집 완료."print_separator# 계속할지 물어보기echo ""if confirm "시스템 점검을 계속하시겠습니까"; then log_info "점검을 계속합니다." # 추가 점검 작업 ...else log_warn "점검을 중단합니다."fi
두 파일을 같은 디렉토리에 놓고 실행합니다.
chmod +x system_info.sh./system_info.sh
실행 결과는 다음과 같습니다.
==================================================
시스템 정보 보고서
==================================================
[INFO] 20:00:01 정보 수집 시작...
호스트명: ubuntu-server
사용자: ubuntu
운영체제: Ubuntu 24.04 LTS
커널 버전: 6.8.0-45-generic
가동 시간: up 2 hours, 15 minutes
CPU: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
메모리: 사용 중: 1240MB / 전체: 3936MB
디스크(/): 사용 중: 8.2G / 전체: 49G (18%)
[INFO] 20:00:01 정보 수집 완료.
==================================================
시스템 점검을 계속하시겠습니까? [y/N]
source로 불러온 lib_utils.sh의 함수(log_info, print_green, confirm, print_separator, print_header)를 마치 이 파일에 직접 정의한 것처럼 쓰고 있습니다. 라이브러리를 한 번 잘 만들어두면, 이후 스크립트를 작성하는 시간이 크게 줄어듭니다. 다음 절의 배열 실습과 PART 05 최종 실습에서도 이 lib_utils.sh를 계속 활용합니다.