🎯 목표: 반복 작업을 자동화하여 생산성을 극대화하기
⏰ 예상 시간: 3-4시간
📋 준비물: - 기본 명령어와 고급 명령어에 익숙한 상태 - 터미널 접근 권한 - 텍스트 에디터 (nano, vim 등)
반복 작업에 지치셨나요? 쉘 스크립트로 모든 걸 자동화해보세요! 한 번 만들어두면 평생 써먹을 수 있는 자동화 스크립트를 만들어보겠습니다.
이 가이드를 마치면:
쉘 스크립트는 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 확장자를 붙이는 것이 관례./를 앞에 붙여야 함변수란? 데이터를 저장하는 상자라고 생각하세요!
#!/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. 옵션들:
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. 특별한 변수들:
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"
조건문이란? “만약 ~라면 ~하고, 아니면 ~해라”를 프로그래밍으로 표현한 것입니다.
#!/bin/bash
read -p "나이를 입력하세요: " AGE
if [ $AGE -ge 18 ]; then
echo "성인입니다."
else
echo "미성년자입니다."
fi
🔍 if 문 문법 상세 설명:
1. 기본 구조:
if [ 조건 ]; then
# 조건이 참일 때 실행할 명령어들
elif [ 다른조건 ]; then
# 다른 조건이 참일 때 실행할 명령어들
else
# 모든 조건이 거짓일 때 실행할 명령어들
fi
2. 조건 연산자 (숫자 비교):
[ $a -eq $b ][ $a -ne $b ][ $a -gt $b ][ $a -ge $b ][ $a -lt $b ][ $a -le $b ]3. 조건 연산자 (문자열 비교):
[ “$a” = “$b” ][ “$a” != “$b” ][ -z “$a” ][ -n “$a” ]4. 조건 연산자 (파일/디렉토리):
[ -f “파일명” ][ -d “디렉토리명” ][ -e “파일명” ][ -r “파일명” ][ -w “파일명” ][ -x “파일명” ]5. 논리 연산자:
[ 조건1 ] && [ 조건2 ][ 조건1 ] || [ 조건2 ][ ! 조건 ]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 “$a” ][ -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="[email protected]" 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 “파일명” ][ -d “디렉토리명” ][ -e “경로” ][ -L “링크명” ]2. 권한 확인 연산자:
[ -r “파일명” ][ -w “파일명” ][ -x “파일명” ]3. 파일 속성 확인 연산자:
[ -s “파일명” ][ -S “파일명” ][ -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"
반복문이란? 같은 작업을 여러 번 반복해야 할 때 사용하는 프로그래밍 구조입니다.
#!/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 문이란? 특정 조건이 참인 동안 계속 반복하는 반복문입니다.
#!/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
#!/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" "작업 완료"
#!/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 "=== 시스템 상태 체크 완료 ==="
#!/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
#!/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"
#!/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 "웹사이트 알림" [email protected]
fi
done
크론탭(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
#!/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="[email protected]" 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 "$@"
쉘 스크립트 마스터가 되셨습니다! 🎊
이제 할 수 있는 것들: - ✅ 반복 작업을 자동화하는 스크립트 작성 - ✅ 조건문과 반복문을 활용한 논리적 프로그래밍 - ✅ 시스템 모니터링 및 백업 자동화 - ✅ 크론탭으로 정기 작업 스케줄링 - ✅ 에러 처리와 디버깅이 가능한 안전한 스크립트
실무 활용 팁: - 작은 스크립트부터 시작해서 점진적으로 확장하세요 - 항상 백업과 테스트를 먼저 해보세요 - 로그를 남기고 모니터링하는 습관을 기르세요 - 다른 사람이 이해할 수 있도록 주석을 달아주세요
🎓 다음 단계: 이제 실제 업무에 적용해보세요!
💬 도움이 필요하면:
man bash - Bash 매뉴얼help 명령어 - 내장 명령어 도움말명령어 –help - 명령어별 도움말💡 자동화의 철학: “게으른 사람이 최고의 프로그래머다” - 반복 작업을 자동화하여 더 중요한 일에 집중하세요!