Bash 스크립트 완전 가이드
실무에서 자주 쓰는 명령어와 스크립트 패턴 총정리
read · 산술연산 · 조건문루프 · 함수 · trapawk · sed · grepfind · systemctl · 네트워크
📋 목차
- read 명령어
- 산술 연산
- 위치 파라미터
- 조건문 · test 명령
- 루프 명령 (for/while/until)
- 함수
- 트랩 (trap) 시그널
- grep 고급 옵션 ✨
- awk / sed 명령어 ✨
- find · 유용한 유틸리티
01
read 명령어
빌트인 명령으로 터미널 또는 파일로부터 입력 문자열을 읽을 때 사용합니다.
| 옵션 | 의미 |
|---|---|
| read answer | 표준 입력으로 한 라인을 읽고 answer 변수에 할당 |
| read first last | 공백 기준으로 첫 단어 → first, 나머지 → last |
| read | 한 라인을 읽고 빌트인 $REPLY 변수에 저장 |
| read -a arrayname | 입력을 공백 기준으로 배열 arrayname에 저장 |
| read -e | 대화형 쉘에서 readline 편집 활성화 |
| read -p prompt | 프롬프트를 출력하고 입력 대기, $REPLY에 저장 |
| read -r line | 백슬래시(\)를 이스케이프 처리 없이 그대로 읽음 |
| read -t 초 | 지정한 초 안에 입력 없으면 타임아웃 (종료 상태 1 반환) |
| read -s | 입력 내용을 화면에 표시하지 않음 (비밀번호 입력 등) |
예제 스크립트
bash
#!/bin/bash
# question.sh
echo -e "행복하세요? : \c"
read answer
echo "$answer 라고 대답하셨네요"
read -p "사용하는 리눅스 배포판: "
echo $REPLY
read -a dist # 배열로 읽기
echo "${dist[0]}를 첫 번째로 입력했습니다"
read -s -p "비밀번호 입력: " pw # 입력 숨김
echo
💡 Tip:read -t 5 -p "5초 안에 입력하세요: " ans — 타임아웃을 활용하면 자동화 스크립트에서 사용자 응답을 기다릴 수 있습니다.
02
산술 연산
정수형 연산
| 방법 | 예시 | 설명 |
|---|---|---|
| declare -i | declare -i num=10+5 | 정수형 변수 선언 |
| let | let "i += 5" | 빌트인 정수 연산 |
| (( )) | (( x = 3 * 4 )) | 이중 괄호 산술 (권장) |
| $(( )) | result=$(( 10 % 3 )) | 산술 치환으로 값 저장 |
진수 표기
| 형식 | 예시 | 10진수 결과 |
|---|---|---|
| 2진수 | declare -i x=2#1010 | 10 |
| 8진수 | declare -i x=8#13 | 11 |
| 16진수 | declare -i x=16#ff | 255 |
실수형 연산 (bc / awk)
bash
# bc: 소수점 2자리까지 나눗셈
n=`echo "scale=2; 20 / 3" | bc`
echo $n # → 6.66
# awk: 실수 곱셈
m=`awk -v x=2.66 -v y=5.22 'BEGIN{printf "%.2f\n", x*y}'`
echo $m # → 13.89
# 제곱근 구하기
echo "sqrt(2)" | bc -l # → 1.41421356...
03
위치 파라미터 & 명령라인 아규먼트
| 변수 | 의미 |
|---|---|
| $0 | 실행한 스크립트 이름 |
| $1 … ${10} | 위치 파라미터 (10 이상은 중괄호 필수) |
| $# | 파라미터 개수 |
| “$*” | 모든 파라미터를 하나의 문자열로 → "$1 $2 $3" |
| “$@” | 각 파라미터를 분리된 문자열로 → "$1" "$2" "$3" |
| $? | 직전 명령의 종료 상태 (0=성공, 1=실패) |
| $$ | 현재 쉘의 PID |
| $! | 마지막 백그라운드 프로세스 PID |
✅ $* vs $@: 큰따옴표로 감쌀 때만 차이가 납니다. "$@"는 각 파라미터의 공백을 보존하므로 파일명 처리 등에서 항상 "$@"를 사용하세요.
set 명령으로 파라미터 재설정
bash
set CentOS Fedora Ubuntu # 위치 파라미터 재설정 echo $* # CentOS Fedora Ubuntu set $(date) # date 출력으로 파라미터 재설정 echo "오늘은 $2 $3 $1" set -- # 모든 파라미터 초기화
04
조건문 & test 명령
문자열 테스트
| 연산자 | 참(true)일 때 |
|---|---|
| [ str1 == str2 ] | 문자열이 같을 때 |
| [ str1 != str2 ] | 문자열이 다를 때 |
| [ -z str ] | 문자열 길이가 0 (빈 문자열) |
| [ -n str ] | 문자열 길이가 0이 아님 |
| [[ str == pat* ]] | 글로브 패턴 매칭 |
| [[ str =~ regex ]] | 정규식 매칭 (bash 3.0+) |
정수형 테스트
| 연산자 | 의미 | (( )) 동등 표현 |
|---|---|---|
| -eq | 같음 (equal) | == |
| -ne | 다름 (not equal) | != |
| -gt | 초과 (greater than) | > |
| -ge | 이상 (greater or equal) | >= |
| -lt | 미만 (less than) | < |
| -le | 이하 (less or equal) | <= |
파일 테스트
| 연산자 | 참일 때 |
|---|---|
| -e filename | 파일이 존재 |
| -f filename | 일반 파일 |
| -d filename | 디렉터리 |
| -r filename | 읽기 가능 |
| -w filename | 쓰기 가능 |
| -x filename | 실행 가능 |
| -s filename | 크기가 0보다 큼 |
| -L filename | 심볼릭 링크 |
| -z filename | 파일 크기가 0 (빈 파일) |
| file1 -nt file2 | file1이 더 최근에 수정됨 |
| file1 -ot file2 | file1이 더 오래됨 |
if / elif / else 패턴
bash
#!/bin/bash
# qa.sh — 점수 판정
read -p "점수 입력 (0-100): " num
if [[ ! $num =~ ^[0-9]+$ ]]; then
echo "숫자를 입력하세요."; exit 1
elif (( num < 70 )); then echo "70점 미만"
elif (( num < 80 )); then echo "70점대"
elif (( num < 90 )); then echo "80점대"
elif (( num < 100 )); then echo "90점대"
else echo "만점! 🎉"
fi
case 명령
bash
read -p "색 입력: " color
case $color in
[Bb]l??) echo "파란색" ;;
[Gg]ree*) echo "녹색" ;;
red|orange) echo "빨간색/주황" ;;
*) echo "알 수 없음" ;;
esac
05
루프 명령 (for / while / until / select)
for 루프
bash
# 목록 순회
for name in 홍길동 장보고 이순신; do
echo "안녕하세요, $name님"
done
# C 스타일 (bash 전용)
for (( i=1; i<=5; i++ )); do
echo $i
done
# 범위 지정 (brace expansion)
for i in {1..10..2}; do # 1 3 5 7 9 (step=2)
echo $i
done
# 파일 목록 처리
for file in /var/log/*.log; do
echo "처리 중: $file"
done
while 루프
bash
# 카운터
number=0
while (( number < 10 )); do
printf "%d " $number
(( number++ ))
done
# 파일을 한 줄씩 읽기
while IFS= read -r line; do
echo "$line"
done < /etc/passwd
until 루프
bash
# 조건이 참이 될 때까지 반복 (while의 반대)
hour=0
until (( hour >= 24 )); do
case $hour in
[0-9]|1[01]) echo "${hour}시: 오전" ;;
12) echo "12시: 정오" ;;
*) echo "${hour}시: 오후" ;;
esac
(( hour++ ))
done
루프 제어 — break / continue / shift
| 명령 | 동작 |
|---|---|
| break | 현재 루프 즉시 종료 |
| break n | n번째 바깥쪽 루프까지 종료 |
| continue | 루프 최상단으로 이동 (다음 반복) |
| continue n | n번째 바깥쪽 루프 다음 반복으로 이동 |
| shift n | 파라미터 목록을 n칸 좌측으로 이동 (기본값 1) |
06
함수
함수는 현재 쉘 컨텍스트에서 실행되며 자식 프로세스를 생성하지 않습니다.
| 개념 | 설명 |
|---|---|
| local 변수 | 함수 내부에서만 유효, 종료 시 자동 제거 |
| return n | 함수 종료 및 종료 상태 반환 (0~255) |
| export -f fn | 함수를 서브쉘로 전달 (전역화) |
| unset -f fn | 함수 정의 제거 |
| declare -f | 정의된 함수 목록과 내용 출력 |
| source ./file | 외부 파일의 함수를 현재 스크립트에서 사용 |
bash
#!/bin/bash
# 기본 함수 정의
greet() {
local name=$1
echo "안녕하세요, ${name}님!"
}
# 반환값 활용
square() {
local result
(( result = $1 * $1 ))
echo $result # echo로 값 출력 → 명령치환으로 받음
}
greet "홍길동"
val=$(square 5)
echo "5의 제곱: $val" # → 25
# 외부 함수 파일 로드
source ./myfunction
os
💡 반환값 패턴:return은 0~255 정수만 반환 가능합니다. 문자열이나 큰 숫자는 echo로 출력하고 $(함수명)으로 받는 패턴을 사용하세요.
07
트랩 (trap) 시그널 처리
| 시그널 | 번호 | 발생 조건 |
|---|---|---|
| SIGHUP | 1 | 터미널 연결 끊김 |
| SIGINT | 2 | Ctrl+C |
| SIGQUIT | 3 | Ctrl+\ |
| SIGKILL | 9 | 강제 종료 (trap 불가) |
| SIGTERM | 15 | kill 명령 기본값 |
| SIGTSTP | 20 | Ctrl+Z (일시중지) |
| EXIT | 0 | 스크립트 종료 시 |
bash
#!/bin/bash # 종료 시 임시 파일 자동 정리 (EXIT 트랩) TMPFILE=$(mktemp) trap "rm -f $TMPFILE; echo '정리 완료'" EXIT # Ctrl+C 가로채기 trap 'echo "중단하려면 \"stop\" 입력"' INT # 시그널 무시 trap "" HUP # HUP 시그널 무시 # 기본 동작으로 복원 trap - INT # INT 시그널 기본값으로 복원 # 트랩 목록 확인 trap -p # 현재 설정된 트랩 출력
✅ 실무 패턴:trap "cleanup; exit" INT TERM EXIT — 임시 파일, 락 파일 정리에 EXIT 트랩을 적극 활용하세요.
08
grep 고급 옵션 NEW
grep은 파일이나 표준 입력에서 패턴과 일치하는 줄을 검색합니다.
| 옵션 | 의미 | 예시 |
|---|---|---|
| -i | 대소문자 구분 없이 검색 | grep -i error log.txt |
| -v | 패턴과 일치하지 않는 줄 출력 | grep -v "#" config |
| -n | 줄 번호 함께 출력 | grep -n "main" script.sh |
| -c | 매칭된 줄 수만 출력 | grep -c "error" app.log |
| -l | 매칭된 파일명만 출력 | grep -l "TODO" *.sh |
| -r | 하위 디렉터리 재귀 검색 | grep -r "function" /scripts |
| -E | 확장 정규식 사용 (egrep 동일) | grep -E "err|warn" log |
| -w | 단어 단위로 정확히 매칭 | grep -w "root" /etc/passwd |
| -A n | 매칭 줄 이후 n줄 함께 출력 | grep -A 3 "ERROR" log |
| -B n | 매칭 줄 이전 n줄 함께 출력 | grep -B 2 "ERROR" log |
| -C n | 앞뒤 n줄 모두 출력 | grep -C 2 "ERROR" log |
| –color | 매칭 부분을 색상으로 강조 | grep --color "root" /etc/passwd |
bash
# 실무 활용 예제 # 로그에서 ERROR 또는 WARN 검색, 줄번호 포함 grep -nE "ERROR|WARN" /var/log/syslog # 주석·공백 제거 후 설정 파일 확인 grep -vE "^#|^$" /etc/ssh/sshd_config # 프로세스 목록에서 특정 프로세스 확인 (grep 자신 제외) ps aux | grep -v grep | grep nginx # 재귀 검색 + 파일명만 출력 grep -rl "#!/bin/bash" /home/ # 여러 패턴 동시 검색 grep -e "error" -e "fail" -e "crash" app.log
09
awk / sed 명령어 NEW
awk — 필드 기반 텍스트 처리
awk는 파일을 레코드(행)와 필드(열)로 분리하여 처리하는 강력한 도구입니다.
| 변수/패턴 | 의미 |
|---|---|
| $0 | 전체 라인 |
| $1, $2, … | 공백 기준 n번째 필드 |
| NF | 현재 행의 필드 수 (마지막 필드: $NF) |
| NR | 현재 처리 중인 줄 번호 |
| FS | 필드 구분자 (기본: 공백/탭) |
| OFS | 출력 필드 구분자 |
| BEGIN{} | 파일 처리 전 실행되는 블록 |
| END{} | 파일 처리 후 실행되는 블록 |
bash
# 기본: 2번째 필드 출력
awk '{print $2}' file.txt
# 구분자 지정 (-F): /etc/passwd에서 사용자명·쉘 출력
awk -F: '{print $1, $7}' /etc/passwd
# 조건부 출력: 3번째 필드가 1000 이상인 행
awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd
# BEGIN/END: 합계 계산
awk 'BEGIN{sum=0} {sum+=$1} END{print "합계:", sum}' numbers.txt
# 줄 번호 추가
awk '{print NR"\t"$0}' file.txt
# 특정 패턴이 있는 줄만 처리
awk '/ERROR/{print NR, $0}' app.log
# printf로 정렬 출력
awk -F: '{printf "%-15s %s\n", $1, $6}' /etc/passwd
sed — 스트림 편집기
sed는 파일을 직접 수정하거나 파이프라인에서 텍스트를 변환할 때 사용합니다.
| 명령 | 의미 | 예시 |
|---|---|---|
| s/old/new/ | 첫 번째 매칭 치환 | sed 's/foo/bar/' |
| s/old/new/g | 전체 치환 | sed 's/foo/bar/g' |
| s/old/new/i | 대소문자 무시 치환 | sed 's/FOO/bar/gI' |
| d | 줄 삭제 | sed '/^#/d' |
| p | 줄 출력 (-n과 함께) | sed -n '5p' |
| a\ text | 지정 줄 다음에 추가 | sed '3a\ 추가내용' |
| i\ text | 지정 줄 앞에 삽입 | sed '1i\ 제목' |
| -i | 파일 직접 수정 (in-place) | sed -i 's/old/new/g' f |
| -n | 자동 출력 억제 | sed -n '1,5p' file |
bash
# 특정 줄 범위 출력 (5~10번째 줄) sed -n '5,10p' file.txt # 주석·빈 줄 제거 sed -E '/^#|^$/d' config.conf # 파일 직접 수정 (백업 생성: .bak) sed -i.bak 's/192.168.1.1/10.0.0.1/g' config.txt # 여러 명령 동시 실행 (-e) sed -e 's/foo/bar/g' -e '/^$/d' file.txt # 특정 줄 삭제 (3번째 줄) sed '3d' file.txt # 패턴 사이 줄 추출 sed -n '/START/,/END/p' file.txt
⚠️ 주의:sed -i는 원본 파일을 직접 수정합니다. 중요 파일은 반드시 sed -i.bak으로 백업을 생성하세요.
10
find & 유용한 유틸리티
find 주요 옵션
| 옵션 | 의미 |
|---|---|
| -name 패턴 | 파일명으로 검색 (와일드카드 가능) |
| -type f/d/l | 타입: 일반파일/디렉터리/심볼릭링크 |
| -mtime +n/-n | n일 초과/이내 수정된 파일 |
| -size +n/-n | n블록 초과/미만 파일 (k=KB, M=MB) |
| -perm nnn | 퍼미션이 nnn인 파일 |
| -user 유저명 | 특정 소유자의 파일 |
| -exec cmd {} | 검색된 파일에 명령 실행 |
| -delete | 검색된 파일 삭제 |
| -maxdepth n | 탐색 깊이 제한 |
bash
# 30일 이상 된 로그 파일 삭제
find /var/log -name "*.log" -mtime +30 -delete
# 퍼미션 755인 파일 검색
find . -type f -perm 755
# 빈 파일 검색 후 삭제
find . -empty -type f -delete
# 검색 결과로 명령 실행
find . -name "*.sh" -exec chmod +x {} \;
# xargs와 결합 (더 빠름)
find /tmp -name "core" -type f | xargs rm -f
유용한 텍스트 처리 유틸리티
| 명령 | 설명 | 예시 |
|---|---|---|
| cut -f2 | 탭 구분 n번째 필드 추출 | cut -f2 file.txt |
| cut -d: -f1 | 구분자 지정 후 필드 추출 | cut -d: -f1 /etc/passwd |
| paste f1 f2 | 두 파일을 열 방향으로 합치기 | paste sname sprice |
| join f1 f2 | 공통 키 기준으로 파일 합치기 | join sname sprice |
| tr a-z A-Z | 소문자 → 대문자 변환 | echo "hello" | tr a-z A-Z |
| tr -d ‘\r’ | Windows 개행 제거 | tr -d '\r' < win.txt |
| uniq | 인접 중복 라인 제거 | sort file | uniq |
| uniq -c | 중복 횟수와 함께 출력 | sort file | uniq -c | sort -rn |
| tee file | 표준 출력 + 파일 동시 저장 | ls | tee list.txt |
| split -l n | n줄 단위로 파일 분할 | split -l 100 large.txt |
| wc -l/-w/-c | 줄수/단어수/바이트수 계산 | wc -l file.txt |
| sort -n/-r/-k | 숫자/역순/키 기준 정렬 | sort -k2 -n file |