Linux 쉘스크립트(Bash) 작성 가이드

쉘스크립트란?

쉘스크립트(Shell Script)는 Linux/Unix 셸에서 실행되는 명령어 모음 파일입니다. 확장자 .sh로 저장하며, 서버 관리, 배포 자동화, 크론잡 등 시스템 운영의 핵심 도구입니다. 대부분의 Linux 배포판에서 기본 셸인 Bash(Bourne Again Shell)를 기준으로 설명합니다.

이 글에서는 기본 문법, 변수, 조건문, 반복문, 함수, 그리고 실전 자동화 스크립트까지 다룹니다.

첫 번째 스크립트

쉘스크립트의 첫 줄은 셔뱅(Shebang) #!/bin/bash로 시작합니다. 이 줄이 운영체제에게 어떤 인터프리터로 실행할지 알려줍니다.

#!/bin/bash
# hello.sh — 첫 번째 쉘스크립트

echo "안녕하세요, 쉘스크립트입니다!"
echo "현재 사용자: $(whoami)"
echo "현재 경로: $(pwd)"
echo "오늘 날짜: $(date '+%Y-%m-%d %H:%M')"

스크립트를 실행하려면 실행 권한을 부여해야 합니다.

# 실행 권한 부여 후 실행
chmod +x hello.sh
./hello.sh
# 안녕하세요, 쉘스크립트입니다!
# 현재 사용자: ubuntu
# 현재 경로: /home/ubuntu
# 오늘 날짜: 2026-04-07 22:00

$(명령어) 구문은 명령어의 실행 결과를 문자열로 치환합니다. 백틱(`명령어`)과 동일한 기능이지만, 중첩이 가능한 $() 형태를 권장합니다.

변수

변수 선언 시 = 양쪽에 공백이 없어야 합니다. 참조할 때는 $변수 또는 ${변수}를 사용합니다.

#!/bin/bash
# 변수 선언 (= 양쪽 공백 금지!)
PROJECT="my-app"
VERSION="2.1.0"
BUILD_DIR="/opt/${PROJECT}/build"

echo "프로젝트: ${PROJECT} v${VERSION}"
echo "빌드 경로: ${BUILD_DIR}"

# 읽기 전용 변수
readonly MAX_RETRY=3

# 환경변수 내보내기 (자식 프로세스에 전달)
export API_KEY="your-secret-key"

# 사용자 입력
read -p "배포할 환경을 선택하세요 (dev/prod): " ENV
echo "선택된 환경: ${ENV}"
구문설명예시
$VAR변수 참조echo $HOME
${VAR}명시적 참조 (권장)echo ${HOME}/bin
${VAR:-기본값}변수 미설정 시 기본값${PORT:-8080}
${VAR:?에러메시지}변수 미설정 시 에러${DB_HOST:?필수값}
${#VAR}문자열 길이${#PROJECT} → 6
$1, $2위치 매개변수./script.sh arg1 arg2
$@모든 인수 (개별)for arg in "$@"
$#인수 개수if [ $# -eq 0 ]
$?직전 명령 종료 코드0=성공, 1+=실패

조건문

Bash의 조건문은 if [ 조건 ] 또는 if [[ 조건 ]] 형태입니다. [[ ]]는 Bash 확장 구문으로, 패턴 매칭과 정규표현식을 지원합니다.

#!/bin/bash
# 조건문 예제

# 숫자 비교
COUNT=15
if [ "${COUNT}" -gt 10 ]; then
    echo "${COUNT}는 10보다 큽니다"
elif [ "${COUNT}" -eq 10 ]; then
    echo "${COUNT}는 10과 같습니다"
else
    echo "${COUNT}는 10보다 작습니다"
fi

# 문자열 비교
ENV="production"
if [[ "${ENV}" == "production" ]]; then
    echo "프로덕션 환경 — 주의해서 작업하세요"
fi

# 파일/디렉토리 확인
CONFIG="/etc/app/config.yaml"
if [ -f "${CONFIG}" ]; then
    echo "설정 파일 존재: ${CONFIG}"
elif [ -d "/etc/app" ]; then
    echo "디렉토리는 있지만 설정 파일 없음"
else
    echo "디렉토리도 없습니다"
fi
숫자 비교의미파일 테스트의미
-eq같다-f파일 존재
-ne다르다-d디렉토리 존재
-gt크다-r읽기 권한 있음
-ge크거나 같다-w쓰기 권한 있음
-lt작다-x실행 권한 있음
-le작거나 같다-s파일 크기 > 0

반복문과 함수

for, while 반복문과 함수를 조합하면 복잡한 자동화 로직을 구현할 수 있습니다.

#!/bin/bash
# 반복문과 함수 예제

# for: 배열 순회
SERVERS=("web01" "web02" "db01" "cache01")
for server in "${SERVERS[@]}"; do
    echo "서버 점검: ${server}"
done

# for: 숫자 범위
for i in {1..5}; do
    echo "카운트: ${i}"
done

# while: 조건 반복 (파일 한 줄씩 읽기)
while IFS= read -r line; do
    echo "읽은 줄: ${line}"
done < /etc/hostname

# 함수 정의와 호출
log() {
    local level="$1"
    local message="$2"
    echo "[$(date '+%H:%M:%S')] [${level}] ${message}"
}

check_service() {
    local service="$1"
    if systemctl is-active --quiet "${service}"; then
        log "INFO" "${service} 정상 실행 중"
        return 0
    else
        log "WARN" "${service} 중지됨"
        return 1
    fi
}

# 함수 호출
check_service "nginx"

함수 내에서 local 키워드로 지역 변수를 선언하면 함수 밖의 변수에 영향을 주지 않습니다. 함수의 반환값은 return으로 종료 코드(0~255)를 반환하며, 문자열 반환이 필요하면 echo$()를 조합합니다.

실전 스크립트: 로그 정리 자동화

지정된 디렉토리에서 오래된 로그 파일을 압축하고 삭제하는 스크립트입니다. 크론잡으로 매일 실행하면 디스크 공간을 자동 관리할 수 있습니다.

#!/bin/bash
# log-cleanup.sh — 로그 파일 정리 자동화
set -euo pipefail  # 에러 시 즉시 종료, 미정의 변수 에러, 파이프 에러 전파

LOG_DIR="${1:-/var/log/app}"
DAYS_TO_COMPRESS=7
DAYS_TO_DELETE=30
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

log() { echo "[${TIMESTAMP}] $1"; }

# 디렉토리 확인
if [ ! -d "${LOG_DIR}" ]; then
    log "오류: ${LOG_DIR} 디렉토리가 존재하지 않습니다"
    exit 1
fi

# 1. 7일 이상 된 로그 → gzip 압축
COMPRESS_COUNT=$(find "${LOG_DIR}" -name "*.log" -mtime +${DAYS_TO_COMPRESS} -type f | wc -l)
if [ "${COMPRESS_COUNT}" -gt 0 ]; then
    find "${LOG_DIR}" -name "*.log" -mtime +${DAYS_TO_COMPRESS} -type f -exec gzip {} \;
    log "${COMPRESS_COUNT}개 로그 파일 압축 완료"
else
    log "압축 대상 없음"
fi

# 2. 30일 이상 된 압축 파일 → 삭제
DELETE_COUNT=$(find "${LOG_DIR}" -name "*.gz" -mtime +${DAYS_TO_DELETE} -type f | wc -l)
if [ "${DELETE_COUNT}" -gt 0 ]; then
    find "${LOG_DIR}" -name "*.gz" -mtime +${DAYS_TO_DELETE} -type f -delete
    log "${DELETE_COUNT}개 압축 파일 삭제 완료"
else
    log "삭제 대상 없음"
fi

# 3. 디스크 사용량 보고
USAGE=$(du -sh "${LOG_DIR}" | awk '{print $1}')
log "현재 로그 디렉토리 크기: ${USAGE}"

set -euo pipefail은 Bash 스크립트의 안전장치로, 프로덕션 스크립트에서는 항상 사용을 권장합니다.

옵션효과
-e명령 실패 시 스크립트 즉시 종료
-u미정의 변수 사용 시 에러
-o pipefail파이프라인 중 하나라도 실패하면 전체 실패

크론잡 등록 예시: crontab -e에서 0 2 * * * /opt/scripts/log-cleanup.sh /var/log/app >> /var/log/cleanup.log 2>&1 — 매일 새벽 2시에 실행됩니다.

정리

쉘스크립트는 Linux 서버 관리의 필수 도구입니다. 핵심 포인트를 정리하면 다음과 같습니다.

  • #!/bin/bash로 시작, chmod +x로 실행 권한 부여
  • 변수 = 양쪽 공백 금지, 참조 시 ${변수} 중괄호 권장
  • 조건문은 [ ] 또는 [[ ]], 숫자 비교 -eq/-gt, 파일 테스트 -f/-d
  • 함수에서 local로 지역 변수, return으로 종료 코드 반환
  • set -euo pipefail을 프로덕션 스크립트에 반드시 포함
  • find, awk, grep 등 CLI 도구와 조합하면 강력한 자동화 가능

이 글이 도움이 되었나요?