개요
쉘 스크립트로 자동화 작업을 하다 보면 한 번쯤 마주치는 쉘 스크립트의 기이한 미스터리가 있죠?
바로 if
문을 쓸 때마다 등장하는 대괄호의 사용 방식인데요!
# 이런 코드도 있고...
if [ -z "$username" ]; then ...
# 저런 코드도 있고...
if [[ "$?" -ne 0 ]]; then ...
# 심지어 괄호가 아예 없는 코드도?!
if id "$username" &>/dev/null; then ...
"대체 언제 [ .. ]
를 쓰고, 언제 [[ .. ]]
를 쓰는 거지? 왜 어떤 건 괄호 조차도 없는거야!"
이런 고민을 해보셨다면, 잘 찾아오셨습니다.
오늘은 이 세 가지 방식의 차이점과 각각의 사용법을 속 시원하게 파헤쳐 보겠습니다.
if
문의 역할
프로그래밍을 접해보셨다면 if
문이 어떤 상황에서 사용하는지는 대강 다 아실거라고 생각합니다.
쉘 스크립트에서의 if
문은 뒤에 오는 명령어의 '종료 코드(Exit code)'를 확인 하는 역할을 합니다.
- 종료 코드 0: 명렁어 성공!
- 종료 코드 0 이외의 값: 명령어 실패!
if
는 명령어가 성공(0
)했을 때 then
절을 실행합니다.
우리가 사용하는 [
나 [[
역시 조건을 평가한 후 성공 또는 실패 코드를 반환하는 '명령어'일 뿐입니다.
이 사실을 인지하고 있으면 모든 것이 훨씬 쉬워집니다.
1. [ ]
단일 대괄호
가장 전톡적이고 기본적인 조건 검사 도구라고 합니다.
test
명령어와 100% 동일하게 작동하며, 오래된 유닉스 시스템부터 최신 리눅스까지 돌아가기 때문에 호환성 이 가장 큰 장점입니다.
특징
test
명령어의 단축 표현입니다.- 변수는 반드시 큰따옴표(
"
)로 감싸야 안전합니다. (변수가 비어있으면 에러 발생) - 파일, 문자열, 숫자 등 기본적인 비교만 가능합니다.
AND/OR
연산자로-a
,-o
를 사용합니다.
언제 사용할까요?
- 스크립트가 어떤 쉘 환경에서 실행될지 모를 때 (최고의 호환성이 필요할 때)
- 간단한 파일 존재 여부나 변수 비교를 할 때
예시 코드
#!/bin/sh
# 사용자가 이름을 입력했는지 확인
read -p "사용자 이름을 입력하세요: " username
if [ -z "$username" ]; then
echo "오류: 사용자 이름은 비워둘 수 없습니다."
exit 1
fi
echo "안녕하세요, $username 님!"
잊지 마세요! [
와 ]
는 단어가 아닌 명령어입니다. 따라서 [ "$var" ]
처럼 괄호 안쪽에 항상 공백을 넣어주어야 합니다.
2. [[ ]]
이중 대괄호
[[ ]]
는 Bash, Zsh 같은 현대적인 쉘이 제공하는 강력하고 향상된 버전의 테스트 기능입니다.
실수를 줄여주고 더 많은 기능을 제공하기 때문에, 특별한 이유가 없다면 가장 추천하는 방식입니다.
특징
[ ]
의 모든 기능을 포함하며 더 안정적입니다.- 변수를 따옴표로 감싸지 않아도 대부분 안전하게 처리됩니다. (그래도 습관적으로 감싸는 게 좋습니다!)
&&
,||
같은 직관적인 논리 연산자를 사용할 수 있습니다.- 패턴 매칭, 정규 표현식 등 고급 문자열 처리가 가능합니다.
언제 사용할까요?
- 스크립트가 Bash나 Zsh 환경에서 실행될 것이 확실할 때 (사실상 거의 모든 경우)
- 복잡한 조건을 조합하거나, 특정 패턴으로 문자열을 검사해야 할 때
예시 코드
#!/bin/bash
# 스크립트 인자로 .log 파일이 주어졌는지 확인
if [[ "$1" == *.log && -f "$1" ]]; then
echo "'$1'은(는) 존재하는 로그 파일입니다."
echo "내용을 분석합니다..."
else
echo "오류: 존재하는 .log 파일을 인자로 전달해주세요."
exit 1
fi
# 이메일 형식 검사 (정규 표현식)
email="test@example.com"
if [[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$ ]]; then
echo "올바른 이메일 형식입니다."
fi
3. 괄호 없음
if
문의 본질을 가장 잘 보여주는 방식이죠.
grep
, ping
, id
등과 같이 실행 결과만으로 성공/실패를 알 수 있는 명령어는 괄호 없이 직접 사용하여 코드를 훨씬 더 직관적으로 만들 수 있답니다.
특징
- 명령어의 성공(종료 코드 0) 여부 자체가 조건이 됩니다.
- 코드가 간결하고, 읽는 사람이 명령어의 역할을 바로 이해할 수 있습니다.
- "만약
grep
으로 단어를 찾는 데 성공했다면..." 처럼 자연스럽게 읽힙니다.
언제 사용할까요?
- 특정 사용자가 시스템에 존재하는지 확인할 때 (
id
,getent
) - 파일 안에 특정 텍스트가 있는지 찾을 때 (
grep
) - 특정 서버가 온라인 상태인지 확인할 때 (
ping
,nc
)
예시 코드
#!/bin/bash
# 1. 'nginx' 사용자가 시스템에 존재하는지 확인
if id "nginx" &>/dev/null; then
echo "nginx 사용자가 이미 존재합니다."
else
echo "nginx 사용자를 생성합니다..."
# useradd nginx
fi
# 2. 설정 파일에 'enabled = true' 항목이 있는지 확인
if grep -q "enabled = true" /etc/myapp/config.conf; then
echo "애플리케이션이 활성화되어 있습니다. 시작합니다."
# systemctl start myapp
fi
마무리
Bash 스크립트라면 [[ ]]
를 씁시다!
가장 안전하고 제공하는 기능도 많고!
그러나 운영 중인 시스템이 최신 버전과 꽤 벌어져있거나, 스크립트가 아주 오래된 경우라면!
전통적인 []
를 사용하는게 안전할 것 같네요!
(차라리 이런 경우라면 스크립트를 처음부터 짤 것 같기는 합니다만)
읽어주셔서 감사합니다.