파일 테스트와 문자열 비교
실제 스크립트를 작성하다 보면 "이 파일이 있는가?", "이 디렉토리에 쓰기 권한이 있는가?", "이 변수가 비어 있는가?"를 자주 확인하게 됩니다. Bash는 이런 검사를 위한 연산자를 풍부하게 제공합니다.
파일 테스트 연산자
[[ ]] 안에서 사용하는 파일 관련 연산자입니다.
| 연산자 | 참인 경우 |
|---|---|
-e file |
파일이나 디렉토리가 존재함 |
-f file |
일반 파일이 존재함 (디렉토리, 링크 제외) |
-d file |
디렉토리가 존재함 |
-L file |
심볼릭 링크가 존재함 |
-r file |
읽기 권한이 있음 |
-w file |
쓰기 권한이 있음 |
-x file |
실행 권한이 있음 |
-s file |
파일이 존재하고 크기가 0보다 큼 |
-z file |
파일이 존재하고 크기가 0 (빈 파일) |
f1 -nt f2 |
f1이 f2보다 최신 (newer than) |
f1 -ot f2 |
f1이 f2보다 오래됨 (older than) |
file="/etc/hosts"[[ -e "$file" ]] && echo "존재함"[[ -f "$file" ]] && echo "일반 파일"[[ -r "$file" ]] && echo "읽기 가능"[[ -w "$file" ]] && echo "쓰기 가능"[[ -x "$file" ]] && echo "실행 가능"[[ -s "$file" ]] && echo "비어있지 않음"
문자열 비교 연산자
| 연산자 | 참인 경우 |
|---|---|
str1 == str2 |
두 문자열이 같음 |
str1 != str2 |
두 문자열이 다름 |
str1 < str2 |
str1이 사전순으로 앞에 옴 |
str1 > str2 |
str1이 사전순으로 뒤에 옴 |
-z str |
문자열이 비어 있음 (zero length) |
-n str |
문자열이 비어 있지 않음 (non-zero) |
str =~ pattern |
문자열이 정규식 패턴에 매칭됨 |
name="Alice"[[ -z "$name" ]] && echo "비어 있음" || echo "값이 있음"[[ -n "$name" ]] && echo "비어 있지 않음"[[ "$name" == "Alice" ]] && echo "이름이 Alice임"[[ "$name" != "Bob" ]] && echo "Bob이 아님"
<와 >는 [[ ]] 안에서만 사용해야 합니다. [ ] 안에서 쓰면 리다이렉션으로 해석될 수 있습니다.
정수 비교 연산자
문자열 비교의 ==는 숫자에도 쓸 수 있지만, 숫자 크기 비교는 전용 연산자를 사용해야 합니다.
| 연산자 | 의미 |
|---|---|
-eq |
equal (같음) |
-ne |
not equal (다름) |
-lt |
less than (미만) |
-le |
less or equal (이하) |
-gt |
greater than (초과) |
-ge |
greater or equal (이상) |
count=10[[ $count -eq 10 ]] && echo "정확히 10"[[ $count -ne 0 ]] && echo "0이 아님"[[ $count -gt 5 ]] && echo "5보다 큼"[[ $count -le 100 ]] && echo "100 이하"
==로 숫자를 비교하면 문자열로 처리되어 "10" == "10" 식으로 비교합니다. 대부분은 맞지만 "10" == "9" 같은 숫자 크기 비교는 문자열 비교로 틀릴 수 있습니다. 크기 비교에는 반드시 -lt, -gt 등을 사용하세요.
실습. 시스템 정보 체크 스크립트
파일과 디렉토리 존재 여부, 권한, 크기를 종합적으로 점검하는 스크립트입니다.
#!/bin/bash# 새 파일: scripts/sys_check.shPASS=0FAIL=0check() { local desc="$1" local result="$2" if [[ "$result" == "ok" ]]; then echo "[OK] $desc" ((PASS++)) else echo "[FAIL] $desc → $result" ((FAIL++)) fi}echo "=============================="echo " 시스템 점검 시작"echo "=============================="# 필수 파일 확인if [[ -f /etc/hosts ]]; then check "/etc/hosts 존재" "ok"else check "/etc/hosts 존재" "파일 없음"fiif [[ -r /etc/hosts ]]; then check "/etc/hosts 읽기 권한" "ok"else check "/etc/hosts 읽기 권한" "권한 없음"fi# 홈 디렉토리 확인if [[ -d "$HOME" ]]; then check "홈 디렉토리 ($HOME) 존재" "ok"else check "홈 디렉토리 존재" "없음"fiif [[ -w "$HOME" ]]; then check "홈 디렉토리 쓰기 권한" "ok"else check "홈 디렉토리 쓰기 권한" "권한 없음"fi# /tmp 확인if [[ -d /tmp && -w /tmp ]]; then check "/tmp 쓰기 가능" "ok"else check "/tmp 쓰기 가능" "실패"fi# 환경변수 확인if [[ -n "$HOME" ]]; then check "\$HOME 설정됨 ($HOME)" "ok"else check "\$HOME 설정됨" "미설정"fiif [[ -n "$PATH" ]]; then check "\$PATH 설정됨" "ok"else check "\$PATH 설정됨" "미설정"fi# 파일 크기 확인logfile="/var/log/syslog"if [[ -f "$logfile" ]]; then if [[ -s "$logfile" ]]; then size=$(du -sh "$logfile" 2>/dev/null | cut -f1) check "$logfile 크기 ($size)" "ok" else check "$logfile 크기" "빈 파일" fielse check "$logfile 존재" "파일 없음"fiecho "=============================="echo "결과: 통과 ${PASS}개, 실패 ${FAIL}개"echo "=============================="[[ $FAIL -eq 0 ]] && exit 0 || exit 1
실행 결과는 다음과 같습니다.
$ bash scripts/sys_check.sh
==============================
시스템 점검 시작
==============================
[OK] /etc/hosts 존재
[OK] /etc/hosts 읽기 권한
[OK] 홈 디렉토리 (/home/ubuntu) 존재
[OK] 홈 디렉토리 쓰기 권한
[OK] /tmp 쓰기 가능
[OK] $HOME 설정됨 (/home/ubuntu)
[OK] $PATH 설정됨
[OK] /var/log/syslog 크기 (2.1M)
==============================
결과: 통과 8개, 실패 0개
==============================
$ echo $?
0
check 함수는 설명과 결과 문자열을 받아 출력 형식을 통일합니다. 함수는 PART 05에서 자세히 다루지만, 반복되는 출력 패턴을 줄이기 위해 미리 사용했습니다.
((PASS++)) 는 PART 03에서 배운 산술 연산입니다. 성공할 때마다 PASS를 하나씩 늘립니다.