====== 쉘 스크립트로 업무 자동화 ======
**🎯 목표**: 반복 작업을 자동화하여 생산성을 극대화하기
**⏰ 예상 시간**: 3-4시간
**📋 준비물**:
- 기본 명령어와 고급 명령어에 익숙한 상태
- 터미널 접근 권한
- 텍스트 에디터 (nano, vim 등)
**반복 작업에 지치셨나요?** 쉘 스크립트로 모든 걸 자동화해보세요!
한 번 만들어두면 평생 써먹을 수 있는 자동화 스크립트를 만들어보겠습니다.
===== 🎯 학습 목표 =====
이 가이드를 마치면:
- **쉘 스크립트**의 기본 문법을 이해할 수 있습니다
- **조건문과 반복문**을 활용한 논리적 프로그래밍이 가능합니다
- **실무에서 바로 쓸 수 있는** 자동화 스크립트를 만들 수 있습니다
- **크론탭**으로 정기적으로 실행되는 작업을 설정할 수 있습니다
===== 🚀 1단계: 쉘 스크립트 첫 만남 =====
==== 쉘 스크립트가 뭔가요? ====
**쉘 스크립트**는 Linux 명령어들을 파일에 저장해서 한 번에 실행할 수 있게 해주는 프로그램입니다.
**예시**:
# 매일 하는 작업들
pwd
ls -la
df -h
ps aux | grep apache
이런 명령어들을 매번 타이핑하는 대신, 스크립트 파일에 저장해두고 한 번에 실행할 수 있습니다!
==== 쉘 스크립트의 기본 구조 ====
**1. 셔뱅(Shebang) - 필수!**
#!/bin/bash
- **의미**: 이 파일이 bash 쉘로 실행되어야 함을 알림
- **위치**: 파일의 첫 번째 줄에 반드시 작성
- **다른 쉘들**:
- ''#!/bin/sh'' - 기본 쉘
- ''#!/usr/bin/python3'' - Python 스크립트
- ''#!/usr/bin/perl'' - Perl 스크립트
**2. 주석(Comment) - 설명을 위한 메모**
# 이것은 한 줄 주석입니다
echo "Hello World" # 이 줄 끝에도 주석 가능
# 여러 줄 주석은 이렇게
# 각 줄마다 #을 붙여야 합니다
**3. 명령어 실행**
# 각 줄은 하나의 명령어
echo "첫 번째 명령어"
ls -la
pwd
**4. 스크립트 종료**
- 스크립트는 마지막 명령어까지 실행 후 자동 종료
- ''exit 0'' - 정상 종료 (선택사항)
- ''exit 1'' - 에러로 종료 (선택사항)
==== 첫 번째 스크립트 만들기 ====
**1. 스크립트 파일 생성**:
nano hello.sh
**2. 스크립트 내용 작성**:
#!/bin/bash
# 이것은 주석입니다
echo "안녕하세요! 첫 번째 쉘 스크립트입니다."
echo "현재 시간: $(date)"
echo "현재 위치: $(pwd)"
**3. 실행 권한 부여**:
chmod +x hello.sh
**4. 스크립트 실행**:
./hello.sh
**🔍 이해하기**:
- ''#!/bin/bash'': 쉘 스크립트임을 알리는 **셔뱅(shebang)**
- ''#'': 주석 (설명)
- ''echo'': 텍스트 출력
- ''$(명령어)'': 명령어 실행 결과를 변수로 사용
**💡 초보자 팁**:
- 스크립트 파일명은 ''.sh'' 확장자를 붙이는 것이 관례
- 파일명에 공백이나 특수문자 사용 금지
- 실행 권한은 한 번만 부여하면 됨 (chmod +x)
- 스크립트 실행 시 ''./''를 앞에 붙여야 함
===== 📝 2단계: 변수와 사용자 입력 =====
==== 변수 사용하기 ====
**변수란?** 데이터를 저장하는 상자라고 생각하세요!
#!/bin/bash
# 변수 선언 (= 앞뒤에 공백 없이!)
NAME="홍길동"
AGE=25
TODAY=$(date +%Y-%m-%d)
# 변수 사용 ($ 붙이기)
echo "이름: $NAME"
echo "나이: $AGE"
echo "오늘 날짜: $TODAY"
# 중괄호로 변수 구분하기
echo "안녕하세요 ${NAME}님!"
**🔍 변수 문법 상세 설명**:
**1. 변수 선언 규칙**:
- **공백 금지**: ''NAME="홍길동"'' (O), ''NAME = "홍길동"'' (X)
- **따옴표 사용**: 공백이 있는 값은 따옴표로 감싸기
- **숫자는 따옴표 없이**: ''AGE=25'' (O), ''AGE="25"'' (O, 하지만 불필요)
**2. 변수 사용 방법**:
- **기본**: ''$변수명'' - ''echo $NAME''
- **중괄호**: ''${변수명}'' - ''echo ${NAME}님''
- **중괄호가 필요한 경우**:
# 변수명이 명확하지 않을 때
echo "${NAME}님" # $NAME님 (X) - 변수명이 NAME님으로 인식됨
**3. 특별한 변수들**:
#!/bin/bash
echo "스크립트 이름: $0"
echo "첫 번째 인수: $1"
echo "모든 인수: $@"
echo "인수 개수: $#"
echo "현재 프로세스 ID: $$"
echo "마지막 명령어 결과: $?"
**4. 변수 타입별 예시**:
#!/bin/bash
# 문자열 변수
NAME="홍길동"
CITY="서울"
# 숫자 변수
AGE=25
COUNT=10
# 명령어 결과를 변수에 저장
CURRENT_TIME=$(date)
FILE_COUNT=$(ls | wc -l)
SYSTEM_INFO=$(uname -a)
# 배열 변수 (고급)
FRUITS=("사과" "바나나" "오렌지")
echo "첫 번째 과일: ${FRUITS[0]}"
==== 사용자 입력 받기 ====
**read 명령어란?** 사용자로부터 키보드 입력을 받는 명령어입니다.
#!/bin/bash
# 사용자 입력 받기
echo "이름을 입력하세요:"
read NAME
echo "나이를 입력하세요:"
read AGE
echo "안녕하세요 ${NAME}님! ${AGE}세이시군요."
**한 줄로 입력받기**:
#!/bin/bash
read -p "이름을 입력하세요: " NAME
read -p "나이를 입력하세요: " AGE
echo "안녕하세요 ${NAME}님! ${AGE}세이시군요."
**🔍 read 명령어 상세 설명**:
**1. 기본 문법**:
read 변수명
**2. 옵션들**:
- **-p "메시지"**: 프롬프트 메시지와 함께 입력받기
- **-s**: 비밀번호처럼 입력 내용을 화면에 표시하지 않기
- **-t 초**: 시간 제한 (초 단위)
- **-n 문자수**: 지정된 문자수만 입력받기
**3. 다양한 입력 방법**:
#!/bin/bash
# 기본 입력
read NAME
# 프롬프트와 함께
read -p "이름: " NAME
# 비밀번호 입력 (화면에 표시 안됨)
read -s -p "비밀번호: " PASSWORD
echo # 줄바꿈
# 시간 제한 (5초)
read -t 5 -p "5초 안에 입력: " QUICK_INPUT
# 여러 변수에 한 번에 입력
read -p "이름과 나이: " NAME AGE
# 배열에 입력
read -a FRUITS -p "과일들 (공백으로 구분): "
echo "첫 번째 과일: ${FRUITS[0]}"
**4. 입력 검증 예시**:
#!/bin/bash
# 숫자 입력 확인
read -p "나이를 입력하세요: " AGE
# 숫자인지 확인
if [[ "$AGE" =~ ^[0-9]+$ ]]; then
echo "올바른 나이입니다: $AGE"
else
echo "숫자를 입력해주세요!"
exit 1
fi
# 빈 입력 확인
read -p "이름을 입력하세요: " NAME
if [[ -z "$NAME" ]]; then
echo "이름을 입력해주세요!"
exit 1
fi
==== 명령줄 인수 사용하기 ====
**명령줄 인수란?** 스크립트 실행 시 함께 전달하는 값들입니다.
#!/bin/bash
# 스크립트 실행 시 전달받은 인수들
echo "스크립트 이름: $0"
echo "첫 번째 인수: $1"
echo "두 번째 인수: $2"
echo "모든 인수: $@"
echo "인수 개수: $#"
**실행 방법**:
./script.sh 안녕 하세요
**🔍 명령줄 인수 상세 설명**:
**1. 특별한 변수들**:
- **$0**: 스크립트 파일명
- **$1, $2, $3...**: 첫 번째, 두 번째, 세 번째 인수
- **$@**: 모든 인수를 배열로
- **$#**: 인수의 개수
- **$***: 모든 인수를 하나의 문자열로
**2. 인수 처리 예시**:
#!/bin/bash
echo "전달받은 인수들:"
echo "스크립트명: $0"
echo "인수 개수: $#"
# 각 인수 출력
for i in {1..$#}; do
echo "인수 $i: ${!i}"
done
# 모든 인수 한 번에 출력
echo "모든 인수: $@"
**3. 인수 검증**:
#!/bin/bash
# 인수가 없으면 도움말 출력
if [ $# -eq 0 ]; then
echo "사용법: $0 <파일명> [옵션]"
echo "예시: $0 test.txt -v"
exit 1
fi
# 최소 인수 개수 확인
if [ $# -lt 2 ]; then
echo "에러: 최소 2개의 인수가 필요합니다."
exit 1
fi
# 특정 인수 확인
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
echo "도움말: 이 스크립트는 파일을 처리합니다."
exit 0
fi
**💡 실습해보기**:
#!/bin/bash
# backup.sh
# 인수 검증
if [ $# -eq 0 ]; then
echo "사용법: $0 <백업할폴더>"
exit 1
fi
# 폴더 존재 확인
if [ ! -d "$1" ]; then
echo "에러: '$1' 폴더가 존재하지 않습니다."
exit 1
fi
BACKUP_DIR=$1
BACKUP_NAME="backup_$(date +%Y%m%d_%H%M%S).tar.gz"
echo "백업 시작: $BACKUP_DIR"
tar -czf $BACKUP_NAME $BACKUP_DIR
echo "백업 완료: $BACKUP_NAME"
**4. 옵션 처리 (고급)**:
#!/bin/bash
# 옵션 변수 초기화
VERBOSE=false
FORCE=false
# 옵션 처리
while [[ $# -gt 0 ]]; do
case $1 in
-v|--verbose)
VERBOSE=true
shift
;;
-f|--force)
FORCE=true
shift
;;
-h|--help)
echo "사용법: $0 [-v] [-f] <파일명>"
exit 0
;;
*)
FILE="$1"
shift
;;
esac
done
echo "파일: $FILE"
echo "상세출력: $VERBOSE"
echo "강제실행: $FORCE"
===== 🔀 3단계: 조건문으로 논리 만들기 =====
==== if 문 기본 사용법 ====
**조건문이란?** "만약 ~라면 ~하고, 아니면 ~해라"를 프로그래밍으로 표현한 것입니다.
#!/bin/bash
read -p "나이를 입력하세요: " AGE
if [ $AGE -ge 18 ]; then
echo "성인입니다."
else
echo "미성년자입니다."
fi
**🔍 if 문 문법 상세 설명**:
**1. 기본 구조**:
if [ 조건 ]; then
# 조건이 참일 때 실행할 명령어들
elif [ 다른조건 ]; then
# 다른 조건이 참일 때 실행할 명령어들
else
# 모든 조건이 거짓일 때 실행할 명령어들
fi
**2. 조건 연산자 (숫자 비교)**:
- **-eq**: 같음 (equal) - ''[ $a -eq $b ]''
- **-ne**: 다름 (not equal) - ''[ $a -ne $b ]''
- **-gt**: 큼 (greater than) - ''[ $a -gt $b ]''
- **-ge**: 크거나 같음 (greater equal) - ''[ $a -ge $b ]''
- **-lt**: 작음 (less than) - ''[ $a -lt $b ]''
- **-le**: 작거나 같음 (less equal) - ''[ $a -le $b ]''
**3. 조건 연산자 (문자열 비교)**:
- **=**: 같음 - ''[ "$a" = "$b" ]''
- **!=**: 다름 - ''[ "$a" != "$b" ]''
- **-z**: 빈 문자열인지 확인 - ''[ -z "$a" ]''
- **-n**: 빈 문자열이 아닌지 확인 - ''[ -n "$a" ]''
**4. 조건 연산자 (파일/디렉토리)**:
- **-f**: 파일인지 확인 - ''[ -f "파일명" ]''
- **-d**: 디렉토리인지 확인 - ''[ -d "디렉토리명" ]''
- **-e**: 존재하는지 확인 - ''[ -e "파일명" ]''
- **-r**: 읽기 가능한지 확인 - ''[ -r "파일명" ]''
- **-w**: 쓰기 가능한지 확인 - ''[ -w "파일명" ]''
- **-x**: 실행 가능한지 확인 - ''[ -x "파일명" ]''
**5. 논리 연산자**:
- **&&**: AND (그리고) - ''[ 조건1 ] && [ 조건2 ]''
- **||**: OR (또는) - ''[ 조건1 ] || [ 조건2 ]''
- **!**: NOT (아님) - ''[ ! 조건 ]''
**6. 다양한 if 문 예시**:
#!/bin/bash
# 기본 if-else
if [ $AGE -ge 18 ]; then
echo "성인입니다."
else
echo "미성년자입니다."
fi
# if-elif-else
if [ $SCORE -ge 90 ]; then
echo "A등급"
elif [ $SCORE -ge 80 ]; then
echo "B등급"
elif [ $SCORE -ge 70 ]; then
echo "C등급"
else
echo "D등급"
fi
# 복합 조건
if [ $AGE -ge 18 ] && [ "$GENDER" = "남성" ]; then
echo "성인 남성입니다."
fi
# 파일 존재 확인
if [ -f "$FILE" ]; then
echo "파일이 존재합니다."
else
echo "파일이 없습니다."
fi
# 문자열 비교
if [ "$NAME" = "홍길동" ]; then
echo "홍길동님 안녕하세요!"
fi
# 빈 문자열 확인
if [ -z "$INPUT" ]; then
echo "입력값이 없습니다."
fi
**7. 대괄호 vs 이중 대괄호**:
#!/bin/bash
# 기본 대괄호 (POSIX 호환)
if [ $AGE -ge 18 ]; then
echo "성인"
fi
# 이중 대괄호 (Bash 확장 기능)
if [[ $AGE -ge 18 ]]; then
echo "성인"
fi
# 이중 대괄호의 장점
if [[ "$STRING" =~ ^[0-9]+$ ]]; then
echo "숫자입니다"
fi
==== 문자열 비교 ====
**문자열 비교란?** 텍스트 값들이 같은지, 다른지, 비어있는지 등을 확인하는 방법입니다.
#!/bin/bash
read -p "비밀번호를 입력하세요: " PASSWORD
if [ "$PASSWORD" = "secret123" ]; then
echo "로그인 성공!"
elif [ "$PASSWORD" = "admin" ]; then
echo "관리자 모드"
else
echo "비밀번호가 틀렸습니다."
fi
**🔍 문자열 비교 상세 설명**:
**1. 기본 비교 연산자**:
- **=**: 같음 - ''[ "$a" = "$b" ]''
- **!=**: 다름 - ''[ "$a" != "$b" ]''
- **-z**: 빈 문자열인지 확인 - ''[ -z "$a" ]''
- **-n**: 빈 문자열이 아닌지 확인 - ''[ -n "$a" ]''
**2. 문자열 비교 예시**:
#!/bin/bash
# 기본 비교
NAME="홍길동"
if [ "$NAME" = "홍길동" ]; then
echo "홍길동님 안녕하세요!"
fi
# 대소문자 구분 비교
if [ "$NAME" = "홍길동" ]; then
echo "정확히 일치합니다"
fi
# 빈 문자열 확인
INPUT=""
if [ -z "$INPUT" ]; then
echo "입력값이 비어있습니다"
fi
# 문자열이 있는지 확인
if [ -n "$NAME" ]; then
echo "이름이 입력되었습니다: $NAME"
fi
# 여러 조건 조합
if [ -n "$NAME" ] && [ "$NAME" != "admin" ]; then
echo "일반 사용자입니다"
fi
**3. 문자열 패턴 매칭 (고급)**:
#!/bin/bash
# 이중 대괄호에서 정규표현식 사용
EMAIL="user@example.com"
if [[ "$EMAIL" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
echo "올바른 이메일 형식입니다"
else
echo "잘못된 이메일 형식입니다"
fi
# 문자열 포함 여부 확인
TEXT="Hello World"
if [[ "$TEXT" == *"World"* ]]; then
echo "World가 포함되어 있습니다"
fi
# 문자열 시작/끝 확인
FILENAME="test.txt"
if [[ "$FILENAME" == *.txt ]]; then
echo "텍스트 파일입니다"
fi
if [[ "$FILENAME" == test* ]]; then
echo "test로 시작하는 파일입니다"
fi
**4. 문자열 조작과 비교**:
#!/bin/bash
# 문자열 길이 확인
TEXT="Hello"
LENGTH=${#TEXT}
echo "문자열 길이: $LENGTH"
if [ $LENGTH -gt 3 ]; then
echo "문자열이 3글자보다 깁니다"
fi
# 부분 문자열 추출
FULL_NAME="홍길동"
FIRST_NAME=${FULL_NAME:0:1} # 첫 번째 글자
echo "성: $FIRST_NAME"
# 문자열 변환
UPPER_TEXT="HELLO"
LOWER_TEXT="hello"
if [ "$UPPER_TEXT" = "${LOWER_TEXT^^}" ]; then
echo "대문자로 변환하면 같습니다"
fi
**5. 실용적인 문자열 비교 예시**:
#!/bin/bash
# 사용자 입력 검증
read -p "사용자명을 입력하세요: " USERNAME
# 빈 입력 확인
if [ -z "$USERNAME" ]; then
echo "에러: 사용자명을 입력해주세요"
exit 1
fi
# 길이 확인
if [ ${#USERNAME} -lt 3 ]; then
echo "에러: 사용자명은 최소 3글자 이상이어야 합니다"
exit 1
fi
# 특수문자 확인 (간단한 방법)
if [[ "$USERNAME" =~ [^a-zA-Z0-9_] ]]; then
echo "에러: 사용자명에는 영문, 숫자, 언더스코어만 사용 가능합니다"
exit 1
fi
echo "사용자명이 유효합니다: $USERNAME"
==== 파일 존재 확인 ====
**파일 확인이란?** 파일이나 디렉토리가 존재하는지, 어떤 권한을 가지고 있는지 확인하는 방법입니다.
#!/bin/bash
FILE="important.txt"
if [ -f "$FILE" ]; then
echo "$FILE 파일이 존재합니다."
echo "파일 크기: $(ls -lh $FILE | awk '{print $5}')"
else
echo "$FILE 파일이 없습니다."
echo "새 파일을 생성하시겠습니까? (y/n)"
read ANSWER
if [ "$ANSWER" = "y" ]; then
touch "$FILE"
echo "파일을 생성했습니다."
fi
fi
**🔍 파일 확인 상세 설명**:
**1. 기본 파일 확인 연산자**:
- **-f**: 일반 파일인지 확인 - ''[ -f "파일명" ]''
- **-d**: 디렉토리인지 확인 - ''[ -d "디렉토리명" ]''
- **-e**: 존재하는지 확인 (파일/디렉토리 모두) - ''[ -e "경로" ]''
- **-L**: 심볼릭 링크인지 확인 - ''[ -L "링크명" ]''
**2. 권한 확인 연산자**:
- **-r**: 읽기 가능한지 확인 - ''[ -r "파일명" ]''
- **-w**: 쓰기 가능한지 확인 - ''[ -w "파일명" ]''
- **-x**: 실행 가능한지 확인 - ''[ -x "파일명" ]''
**3. 파일 속성 확인 연산자**:
- **-s**: 파일 크기가 0보다 큰지 확인 - ''[ -s "파일명" ]''
- **-S**: 소켓 파일인지 확인 - ''[ -S "파일명" ]''
- **-p**: 파이프 파일인지 확인 - ''[ -p "파일명" ]''
**4. 파일 확인 예시**:
#!/bin/bash
# 파일 존재 확인
if [ -f "test.txt" ]; then
echo "test.txt 파일이 존재합니다"
else
echo "test.txt 파일이 없습니다"
fi
# 디렉토리 존재 확인
if [ -d "/home/user" ]; then
echo "/home/user 디렉토리가 존재합니다"
fi
# 파일과 디렉토리 구분
if [ -f "$1" ]; then
echo "$1은 파일입니다"
elif [ -d "$1" ]; then
echo "$1은 디렉토리입니다"
else
echo "$1은 존재하지 않습니다"
fi
# 권한 확인
if [ -r "config.txt" ]; then
echo "config.txt를 읽을 수 있습니다"
fi
if [ -w "log.txt" ]; then
echo "log.txt에 쓸 수 있습니다"
fi
# 파일 크기 확인
if [ -s "data.txt" ]; then
echo "data.txt는 비어있지 않습니다"
else
echo "data.txt는 비어있습니다"
fi
**5. 실용적인 파일 처리 예시**:
#!/bin/bash
# 백업 파일 생성 전 확인
BACKUP_FILE="backup_$(date +%Y%m%d).tar.gz"
if [ -f "$BACKUP_FILE" ]; then
echo "경고: $BACKUP_FILE이 이미 존재합니다"
read -p "덮어쓰시겠습니까? (y/n): " OVERWRITE
if [ "$OVERWRITE" != "y" ]; then
echo "백업을 취소합니다"
exit 1
fi
fi
# 설정 파일 확인
CONFIG_FILE="/etc/myapp.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "설정 파일이 없습니다: $CONFIG_FILE"
echo "기본 설정 파일을 생성합니다"
cp /etc/myapp.conf.default "$CONFIG_FILE"
fi
# 로그 디렉토리 확인 및 생성
LOG_DIR="/var/log/myapp"
if [ ! -d "$LOG_DIR" ]; then
echo "로그 디렉토리를 생성합니다: $LOG_DIR"
mkdir -p "$LOG_DIR"
fi
# 실행 권한 확인
SCRIPT_FILE="install.sh"
if [ -f "$SCRIPT_FILE" ] && [ ! -x "$SCRIPT_FILE" ]; then
echo "실행 권한을 부여합니다: $SCRIPT_FILE"
chmod +x "$SCRIPT_FILE"
fi
**6. 파일 정보 수집**:
#!/bin/bash
# 파일 정보 출력 함수
file_info() {
local FILE="$1"
if [ ! -e "$FILE" ]; then
echo "파일이 존재하지 않습니다: $FILE"
return 1
fi
echo "=== 파일 정보: $FILE ==="
# 파일 타입
if [ -f "$FILE" ]; then
echo "타입: 일반 파일"
elif [ -d "$FILE" ]; then
echo "타입: 디렉토리"
elif [ -L "$FILE" ]; then
echo "타입: 심볼릭 링크"
fi
# 파일 크기
if [ -f "$FILE" ]; then
SIZE=$(ls -lh "$FILE" | awk '{print $5}')
echo "크기: $SIZE"
fi
# 권한
PERMS=$(ls -l "$FILE" | awk '{print $1}')
echo "권한: $PERMS"
# 수정 시간
MTIME=$(ls -l "$FILE" | awk '{print $6, $7, $8}')
echo "수정시간: $MTIME"
}
# 사용 예시
file_info "test.txt"
===== 🔄 4단계: 반복문으로 효율성 높이기 =====
==== for 문 - 목록 반복 ====
**반복문이란?** 같은 작업을 여러 번 반복해야 할 때 사용하는 프로그래밍 구조입니다.
#!/bin/bash
# 파일 목록 반복
echo "현재 폴더의 텍스트 파일들:"
for file in *.txt; do
if [ -f "$file" ]; then
echo "- $file (크기: $(ls -lh "$file" | awk '{print $5}'))"
fi
done
**🔍 for 문 상세 설명**:
**1. 기본 for 문 구조**:
for 변수 in 목록; do
# 반복할 명령어들
done
**2. 다양한 목록 형태**:
#!/bin/bash
# 1. 직접 목록 지정
for fruit in "사과" "바나나" "오렌지"; do
echo "과일: $fruit"
done
# 2. 파일 패턴 사용
for file in *.txt; do
echo "텍스트 파일: $file"
done
# 3. 명령어 결과 사용
for user in $(cat users.txt); do
echo "사용자: $user"
done
# 4. 숫자 범위
for i in {1..5}; do
echo "숫자: $i"
done
# 5. 문자 범위
for letter in {a..e}; do
echo "문자: $letter"
done
**3. 숫자 범위 반복**:
#!/bin/bash
# 기본 범위
for i in {1..10}; do
echo "숫자: $i"
done
# 간격 지정
for i in {0..20..2}; do
echo "짝수: $i"
done
# 역순
for i in {10..1}; do
echo "역순: $i"
done
# C 스타일 for 문 (고급)
for ((i=1; i<=10; i++)); do
echo "C 스타일: $i"
done
**4. 파일 처리 예시**:
#!/bin/bash
# 모든 텍스트 파일 처리
for file in *.txt; do
if [ -f "$file" ]; then
echo "처리 중: $file"
# 파일 처리 작업
wc -l "$file"
fi
done
# 특정 디렉토리의 모든 파일
for file in /home/user/documents/*; do
if [ -f "$file" ]; then
echo "파일: $file"
ls -lh "$file"
fi
done
# 하위 디렉토리까지 모든 파일 (고급)
for file in $(find . -name "*.log"); do
echo "로그 파일: $file"
tail -5 "$file"
done
**5. 배열과 함께 사용**:
#!/bin/bash
# 배열 정의
FRUITS=("사과" "바나나" "오렌지" "포도")
# 배열 요소 반복
for fruit in "${FRUITS[@]}"; do
echo "과일: $fruit"
done
# 배열 인덱스와 함께
for i in "${!FRUITS[@]}"; do
echo "인덱스 $i: ${FRUITS[$i]}"
done
# 명령줄 인수 반복
for arg in "$@"; do
echo "인수: $arg"
done
**6. 중첩 for 문**:
#!/bin/bash
# 구구단 예시
for i in {1..9}; do
echo "=== $i단 ==="
for j in {1..9}; do
result=$((i * j))
echo "$i x $j = $result"
done
echo
done
# 디렉토리와 파일 반복
for dir in */; do
echo "디렉토리: $dir"
for file in "$dir"*.txt; do
if [ -f "$file" ]; then
echo " 파일: $file"
fi
done
done
==== while 문 - 조건 반복 ====
**while 문이란?** 특정 조건이 참인 동안 계속 반복하는 반복문입니다.
#!/bin/bash
# 사용자가 'quit'을 입력할 때까지 반복
echo "명령어를 입력하세요 (quit으로 종료):"
while true; do
read -p "> " COMMAND
if [ "$COMMAND" = "quit" ]; then
echo "프로그램을 종료합니다."
break
elif [ "$COMMAND" = "date" ]; then
date
elif [ "$COMMAND" = "pwd" ]; then
pwd
else
echo "알 수 없는 명령어: $COMMAND"
fi
done
**🔍 while 문 상세 설명**:
**1. 기본 while 문 구조**:
while [ 조건 ]; do
# 반복할 명령어들
done
**2. 다양한 while 문 예시**:
#!/bin/bash
# 카운터 기반 반복
COUNT=1
while [ $COUNT -le 5 ]; do
echo "카운트: $COUNT"
COUNT=$((COUNT + 1))
done
# 파일 읽기
while read line; do
echo "읽은 줄: $line"
done < "파일명.txt"
# 명령어 결과 읽기
ls -1 | while read file; do
echo "파일: $file"
done
# 조건 기반 반복
PASSWORD=""
while [ -z "$PASSWORD" ]; do
read -s -p "비밀번호를 입력하세요: " PASSWORD
echo
done
**3. 카운터 기반 반복**:
#!/bin/bash
# 시스템 상태를 5번 확인
COUNT=1
while [ $COUNT -le 5 ]; do
echo "=== $COUNT 번째 확인 ==="
echo "현재 시간: $(date)"
echo "CPU 사용률: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)"
echo "메모리 사용률: $(free | grep Mem | awk '{printf "%.1f%%", $3/$2 * 100.0}')"
echo
COUNT=$((COUNT + 1))
sleep 2
done
**4. 무한 루프와 제어**:
#!/bin/bash
# 무한 루프 (조건이 항상 참)
while true; do
echo "무한 반복 중... (Ctrl+C로 종료)"
sleep 1
done
# break로 루프 종료
COUNT=1
while true; do
echo "카운트: $COUNT"
if [ $COUNT -eq 10 ]; then
echo "10에 도달했습니다. 종료합니다."
break
fi
COUNT=$((COUNT + 1))
done
# continue로 현재 반복 건너뛰기
for i in {1..10}; do
if [ $i -eq 5 ]; then
echo "5를 건너뜁니다"
continue
fi
echo "숫자: $i"
done
**5. 파일 처리 while 문**:
#!/bin/bash
# 파일을 한 줄씩 읽기
while IFS= read -r line; do
echo "처리 중: $line"
# 각 줄에 대한 처리 작업
done < "input.txt"
# 명령어 결과를 한 줄씩 처리
ps aux | while read -r user pid cpu mem vsz rss tty stat start time command; do
if [ "$cpu" != "%CPU" ]; then # 헤더 제외
echo "프로세스: $command (CPU: $cpu%)"
fi
done
# 대화형 입력 처리
echo "이름과 나이를 입력하세요 (종료하려면 'quit' 입력):"
while true; do
read -p "이름: " NAME
if [ "$NAME" = "quit" ]; then
break
fi
read -p "나이: " AGE
echo "$NAME님은 $AGE세입니다."
done
**6. 조건 기반 반복**:
#!/bin/bash
# 파일이 존재할 때까지 대기
while [ ! -f "ready.txt" ]; do
echo "ready.txt 파일을 기다리는 중..."
sleep 5
done
echo "파일이 준비되었습니다!"
# 네트워크 연결 확인
while ! ping -c 1 google.com &> /dev/null; do
echo "네트워크 연결을 기다리는 중..."
sleep 10
done
echo "네트워크 연결됨!"
# 사용자 입력 검증
while true; do
read -p "1-10 사이의 숫자를 입력하세요: " NUMBER
if [[ "$NUMBER" =~ ^[0-9]+$ ]] && [ $NUMBER -ge 1 ] && [ $NUMBER -le 10 ]; then
echo "올바른 숫자입니다: $NUMBER"
break
else
echo "잘못된 입력입니다. 다시 시도하세요."
fi
done
===== 🛠️ 5단계: 함수로 코드 재사용하기 =====
==== 함수 정의와 사용 ====
#!/bin/bash
# 함수 정의
backup_folder() {
local FOLDER=$1
local BACKUP_NAME="backup_$(basename $FOLDER)_$(date +%Y%m%d_%H%M%S).tar.gz"
echo "백업 시작: $FOLDER"
if tar -czf "$BACKUP_NAME" "$FOLDER"; then
echo "백업 성공: $BACKUP_NAME"
return 0
else
echo "백업 실패: $FOLDER"
return 1
fi
}
# 함수 사용
backup_folder "/home/user/documents"
backup_folder "/home/user/pictures"
==== 로그 함수 만들기 ====
#!/bin/bash
LOG_FILE="/var/log/my_script.log"
# 로그 함수
log_message() {
local LEVEL=$1
local MESSAGE=$2
local TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$TIMESTAMP] [$LEVEL] $MESSAGE" | tee -a "$LOG_FILE"
}
# 사용 예시
log_message "INFO" "스크립트 시작"
log_message "ERROR" "파일을 찾을 수 없습니다"
log_message "SUCCESS" "작업 완료"
===== 📋 6단계: 실무 자동화 스크립트 모음 =====
==== 1. 시스템 상태 체크 스크립트 ====
#!/bin/bash
# system_check.sh
LOG_FILE="/var/log/system_check.log"
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log_message "=== 시스템 상태 체크 시작 ==="
# CPU 사용률 체크
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
log_message "CPU 사용률: ${CPU_USAGE}%"
if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
log_message "WARNING: CPU 사용률이 높습니다!"
fi
# 메모리 사용률 체크
MEM_USAGE=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
log_message "메모리 사용률: ${MEM_USAGE}%"
if (( $(echo "$MEM_USAGE > 90" | bc -l) )); then
log_message "WARNING: 메모리 사용률이 높습니다!"
fi
# 디스크 사용률 체크
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1)
log_message "디스크 사용률: ${DISK_USAGE}%"
if [ "$DISK_USAGE" -gt 85 ]; then
log_message "WARNING: 디스크 사용률이 높습니다!"
fi
log_message "=== 시스템 상태 체크 완료 ==="
==== 2. 자동 백업 스크립트 ====
#!/bin/bash
# auto_backup.sh
BACKUP_SOURCE="/home/user/important_data"
BACKUP_DEST="/backup"
BACKUP_NAME="backup_$(date +%Y%m%d_%H%M%S).tar.gz"
MAX_BACKUPS=7
# 백업 디렉토리 생성
mkdir -p "$BACKUP_DEST"
# 백업 실행
echo "백업 시작: $(date)"
if tar -czf "$BACKUP_DEST/$BACKUP_NAME" "$BACKUP_SOURCE"; then
echo "백업 성공: $BACKUP_NAME"
# 오래된 백업 파일 삭제 (최근 7개만 유지)
cd "$BACKUP_DEST"
ls -t backup_*.tar.gz | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm
echo "백업 완료: $(date)"
else
echo "백업 실패: $(date)"
exit 1
fi
==== 3. 로그 분석 스크립트 ====
#!/bin/bash
# log_analyzer.sh
LOG_FILE="/var/log/syslog"
REPORT_FILE="/tmp/log_report_$(date +%Y%m%d).txt"
echo "=== 로그 분석 리포트 ($(date)) ===" > "$REPORT_FILE"
echo >> "$REPORT_FILE"
# 에러 개수 세기
ERROR_COUNT=$(grep -i "error" "$LOG_FILE" | wc -l)
echo "총 에러 개수: $ERROR_COUNT" >> "$REPORT_FILE"
# 가장 많이 발생한 에러 TOP 5
echo >> "$REPORT_FILE"
echo "=== 가장 많이 발생한 에러 TOP 5 ===" >> "$REPORT_FILE"
grep -i "error" "$LOG_FILE" | awk '{print $5}' | sort | uniq -c | sort -nr | head -5 >> "$REPORT_FILE"
# 시간대별 에러 분포
echo >> "$REPORT_FILE"
echo "=== 시간대별 에러 분포 ===" >> "$REPORT_FILE"
grep -i "error" "$LOG_FILE" | awk '{print $3}' | cut -d: -f1 | sort | uniq -c | sort -nr >> "$REPORT_FILE"
echo "로그 분석 완료: $REPORT_FILE"
==== 4. 웹사이트 상태 모니터링 스크립트 ====
#!/bin/bash
# website_monitor.sh
WEBSITES=("https://google.com" "https://github.com" "https://stackoverflow.com")
LOG_FILE="/var/log/website_monitor.log"
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
for website in "${WEBSITES[@]}"; do
log_message "체크 중: $website"
# HTTP 상태 코드 확인
STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$website")
if [ "$STATUS_CODE" -eq 200 ]; then
log_message "✅ $website - 정상 (HTTP $STATUS_CODE)"
else
log_message "❌ $website - 문제 발생 (HTTP $STATUS_CODE)"
# 이메일 알림 (선택사항)
# echo "웹사이트 문제: $website (HTTP $STATUS_CODE)" | mail -s "웹사이트 알림" admin@company.com
fi
done
===== ⏰ 7단계: 크론탭으로 자동 실행하기 =====
==== 크론탭이 뭔가요? ====
**크론탭(crontab)**은 Linux에서 정해진 시간에 자동으로 스크립트를 실행해주는 스케줄러입니다.
==== 크론탭 설정하기 ====
# 크론탭 편집
crontab -e
# 현재 크론탭 확인
crontab -l
# 크론탭 삭제
crontab -r
==== 크론탭 시간 형식 ====
분 시 일 월 요일 명령어
* * * * * /path/to/script.sh
# 예시:
# 매일 오전 2시에 백업 실행
0 2 * * * /home/user/backup.sh
# 매주 월요일 오전 9시에 시스템 체크
0 9 * * 1 /home/user/system_check.sh
# 매 5분마다 웹사이트 모니터링
*/5 * * * * /home/user/website_monitor.sh
# 매월 1일 오전 3시에 로그 정리
0 3 1 * * /home/user/cleanup_logs.sh
**시간 설정 도우미**:
- ''*'': 모든 값
- ''*/5'': 5분마다
- ''0-23'': 0시부터 23시까지
- ''1,15'': 1일과 15일
- ''1-5'': 월요일부터 금요일까지
==== 실용적인 크론탭 예시 ====
# 매일 오전 2시 - 자동 백업
0 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# 매 10분마다 - 시스템 상태 체크
*/10 * * * * /home/user/scripts/system_check.sh
# 매주 일요일 오전 3시 - 로그 정리
0 3 * * 0 /home/user/scripts/cleanup.sh
# 매월 1일 오전 4시 - 월간 리포트 생성
0 4 1 * * /home/user/scripts/monthly_report.sh
# 평일 오전 9시 - 업무 시작 알림
0 9 * * 1-5 /home/user/scripts/work_start_notification.sh
===== 🔧 8단계: 디버깅과 에러 처리 =====
==== 스크립트 디버깅 ====
#!/bin/bash
# debug_example.sh
# 디버그 모드 켜기
set -x # 실행되는 명령어 모두 출력
set -e # 에러 발생 시 즉시 종료
echo "디버깅 시작"
ls -la
echo "디버깅 끝"
# 디버그 모드 끄기
set +x
**디버깅 옵션**:
- ''set -x'': 실행 명령어 출력
- ''set -e'': 에러 시 즉시 종료
- ''set -u'': 정의되지 않은 변수 사용 시 에러
==== 에러 처리하기 ====
#!/bin/bash
# error_handling.sh
# 에러 처리 함수
handle_error() {
echo "에러 발생: 줄 번호 $1"
echo "마지막 명령어: $2"
exit 1
}
# 에러 트랩 설정
trap 'handle_error $LINENO "$BASH_COMMAND"' ERR
echo "작업 시작"
# 존재하지 않는 파일 복사 시도 (에러 발생)
cp nonexistent.txt backup.txt
echo "이 줄은 실행되지 않습니다"
==== 안전한 스크립트 작성 ====
#!/bin/bash
# safe_script.sh
# 안전한 스크립트 설정
set -euo pipefail
# 변수 초기화
SOURCE_DIR=""
DEST_DIR=""
# 도움말 함수
show_help() {
echo "사용법: $0 -s <원본디렉토리> -d <대상디렉토리>"
echo " -s: 원본 디렉토리 경로"
echo " -d: 대상 디렉토리 경로"
echo " -h: 도움말 출력"
}
# 명령줄 옵션 처리
while getopts "s:d:h" opt; do
case $opt in
s) SOURCE_DIR="$OPTARG" ;;
d) DEST_DIR="$OPTARG" ;;
h) show_help; exit 0 ;;
*) show_help; exit 1 ;;
esac
done
# 필수 인수 확인
if [[ -z "$SOURCE_DIR" || -z "$DEST_DIR" ]]; then
echo "에러: 원본과 대상 디렉토리를 모두 지정해야 합니다."
show_help
exit 1
fi
# 디렉토리 존재 확인
if [[ ! -d "$SOURCE_DIR" ]]; then
echo "에러: 원본 디렉토리가 존재하지 않습니다: $SOURCE_DIR"
exit 1
fi
# 작업 실행
echo "백업 시작: $SOURCE_DIR -> $DEST_DIR"
mkdir -p "$DEST_DIR"
cp -r "$SOURCE_DIR"/* "$DEST_DIR"/
echo "백업 완료"
===== 🎯 실전 프로젝트: 종합 서버 관리 스크립트 =====
#!/bin/bash
# server_manager.sh - 종합 서버 관리 스크립트
# 설정
LOG_FILE="/var/log/server_manager.log"
BACKUP_DIR="/backup"
ALERT_EMAIL="admin@company.com"
CPU_THRESHOLD=80
MEM_THRESHOLD=90
DISK_THRESHOLD=85
# 로그 함수
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 시스템 상태 체크
check_system() {
log "=== 시스템 상태 체크 시작 ==="
# CPU 체크
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
log "CPU 사용률: ${CPU_USAGE}%"
if (( $(echo "$CPU_USAGE > $CPU_THRESHOLD" | bc -l) )); then
log "WARNING: CPU 사용률이 임계값을 초과했습니다!"
send_alert "CPU 사용률 경고: ${CPU_USAGE}%"
fi
# 메모리 체크
MEM_USAGE=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
log "메모리 사용률: ${MEM_USAGE}%"
if (( $(echo "$MEM_USAGE > $MEM_THRESHOLD" | bc -l) )); then
log "WARNING: 메모리 사용률이 임계값을 초과했습니다!"
send_alert "메모리 사용률 경고: ${MEM_USAGE}%"
fi
# 디스크 체크
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1)
log "디스크 사용률: ${DISK_USAGE}%"
if [ "$DISK_USAGE" -gt "$DISK_THRESHOLD" ]; then
log "WARNING: 디스크 사용률이 임계값을 초과했습니다!"
send_alert "디스크 사용률 경고: ${DISK_USAGE}%"
fi
log "=== 시스템 상태 체크 완료 ==="
}
# 백업 실행
run_backup() {
log "=== 백업 시작 ==="
BACKUP_NAME="server_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
mkdir -p "$BACKUP_DIR"
if tar -czf "$BACKUP_PATH" /etc /home /var/www 2>/dev/null; then
log "백업 성공: $BACKUP_NAME"
# 오래된 백업 파일 정리 (7일 이상)
find "$BACKUP_DIR" -name "server_backup_*.tar.gz" -mtime +7 -delete
log "오래된 백업 파일 정리 완료"
else
log "ERROR: 백업 실패"
send_alert "서버 백업 실패"
fi
log "=== 백업 완료 ==="
}
# 로그 정리
cleanup_logs() {
log "=== 로그 정리 시작 ==="
# 30일 이상 된 로그 파일 압축
find /var/log -name "*.log" -mtime +30 -exec gzip {} \;
# 90일 이상 된 압축 로그 파일 삭제
find /var/log -name "*.log.gz" -mtime +90 -delete
log "로그 정리 완료"
}
# 알림 전송
send_alert() {
local MESSAGE="$1"
log "알림 전송: $MESSAGE"
# 이메일 전송 (mail 명령어가 설정되어 있는 경우)
if command -v mail &> /dev/null; then
echo "$MESSAGE" | mail -s "서버 알림" "$ALERT_EMAIL"
fi
}
# 메인 함수
main() {
case "$1" in
"check")
check_system
;;
"backup")
run_backup
;;
"cleanup")
cleanup_logs
;;
"all")
check_system
run_backup
cleanup_logs
;;
*)
echo "사용법: $0 {check|backup|cleanup|all}"
echo " check - 시스템 상태 체크"
echo " backup - 백업 실행"
echo " cleanup - 로그 정리"
echo " all - 모든 작업 실행"
exit 1
;;
esac
}
# 스크립트 실행
main "$@"
===== 🎉 축하합니다! =====
쉘 스크립트 마스터가 되셨습니다! 🎊
**이제 할 수 있는 것들**:
- ✅ 반복 작업을 자동화하는 스크립트 작성
- ✅ 조건문과 반복문을 활용한 논리적 프로그래밍
- ✅ 시스템 모니터링 및 백업 자동화
- ✅ 크론탭으로 정기 작업 스케줄링
- ✅ 에러 처리와 디버깅이 가능한 안전한 스크립트
**실무 활용 팁**:
- 작은 스크립트부터 시작해서 점진적으로 확장하세요
- 항상 백업과 테스트를 먼저 해보세요
- 로그를 남기고 모니터링하는 습관을 기르세요
- 다른 사람이 이해할 수 있도록 주석을 달아주세요
**🎓 다음 단계**: 이제 실제 업무에 적용해보세요!
===== 📚 참고자료 =====
- **Bash 스크립트 가이드**: https://www.gnu.org/software/bash/manual/
- **쉘 스크립트 튜토리얼**: https://www.shellscript.sh/
- **크론탭 생성기**: https://crontab.guru/
- **정규표현식 연습**: https://regexr.com/
**💬 도움이 필요하면**:
- ''man bash'' - Bash 매뉴얼
- ''help 명령어'' - 내장 명령어 도움말
- ''명령어 --help'' - 명령어별 도움말
//💡 **자동화의 철학**: "게으른 사람이 최고의 프로그래머다" - 반복 작업을 자동화하여 더 중요한 일에 집중하세요!//