본문 바로가기
빌드노트 검색

빌드노트

Bash ${VAR-default}가 빈 문자열을 그대로 넘기는 이유

Bash의 ${VAR-default}는 빈 문자열을 그대로 쓴다. 미설정·빈 값의 실제 비교로 :-와 :=를 고르고, 인자에만 기본값을 쓸지 변수에도 저장할지 구분한다. set -u와 공백 값의 한계도 짚는다.

Bash 스크립트에서 ${VAR-default}를 썼는데 VAR=''일 때 실행 인자가 비어 있다면, 기본값 검사에서 콜론이 빠졌는지 확인한다. ${VAR-default}는 변수가 미설정일 때만 기본값을 쓴다. 빈 문자열도 기본값으로 바꾸려면 "${VAR:-default}"를 쓴다. 반대로 빈 문자열이 “명시적으로 비워 둔 설정”이라는 뜻이면 콜론 없는 형태가 맞다.

빈 문자열에서 갈리는 기본값

Linux 또는 WSL의 Bash 터미널에서 다음 블록을 통째로 실행한다. Bash와 env가 필요하다. 새 자식 Bash의 합성 변수만 바꾸므로 현재 터미널의 변수·옵션은 그대로다. env -u BASH_ENV와 시작 옵션은 초기화 파일을 읽지 않기 위한 설정이다. Bash 시작 파일 설명 (새 탭에서 열림)

env -u BASH_ENV bash --noprofile --norc -u <<'BASH'
unset CB_DEFAULT_LAB
printf 'unset: -=<%s> :-=<%s>\n' "${CB_DEFAULT_LAB-fallback}" "${CB_DEFAULT_LAB:-fallback}"
CB_DEFAULT_LAB=
printf 'empty: -=<%s> :-=<%s> stored=<%s>\n' "${CB_DEFAULT_LAB-fallback}" "${CB_DEFAULT_LAB:-fallback}" "$CB_DEFAULT_LAB"
: "${CB_DEFAULT_LAB:=fallback}"
printf 'after :=: <%s>\n' "$CB_DEFAULT_LAB"
BASH

직접 실행한 출력은 다음과 같았다. 꺾쇠는 값의 경계를 표시한다.

unset: -=<fallback> :-=<fallback>
empty: -=<> :-=<fallback> stored=<>
after :=: <fallback>

unset은 변수의 설정을 없애고, CB_DEFAULT_LAB=은 길이 0인 문자열을 대입한다. 두 번째 줄에서 -는 빈 값을 그대로 선택했고 :-는 fallback을 선택했다. 하지만 stored=<>처럼 원래 변수는 여전히 빈 문자열이었다. 세 번째 줄은 :=가 기본값을 변수에도 저장했다는 관찰이다. Bash 매뉴얼의 기본값·대입 조건 (새 탭에서 열림)과 일치한다.

별도 비교에서는 미설정 변수에 -와 :-를 적용해도 변수가 설정되지 않았다. :=는 미설정과 빈 문자열 양쪽에 fallback을 저장했다. 이미 값이 custom이면 세 형태 모두 그 값을 유지했다. -와 :-는 그 자리에서 쓸 값을 고르고, :=는 필요할 때 대입까지 한다.

값을 넘기는 위치를 고친다

자기 Bash 스크립트에서 빈 값도 기본값으로 바꾸려면, 인자에 쓰던 "${VAR-default}"를 다음처럼 고친다. printf는 전달할 값을 꺾쇠 안에 보여 주는 확인용 명령이다.

printf 'arg=<%s>\n' "${VAR:-default}"

이 한 줄도 미설정·빈 문자열에서 각각 실행했을 때 arg=<default>가 나왔다. 값이 custom이면 arg=<custom>이었다. 실제 명령에서도 해당 인자 자리에 "${VAR:-default}"를 넣는다. 빈 문자열이 의도된 설정이면 "${VAR-default}"를 유지한다.

이후 줄에서도 같은 변수의 기본값을 읽어야 한다면 먼저 : "${VAR:=default}"로 초기화한다. 여기서 :는 인자를 확장한 뒤 별도 작업을 하지 않는 내장 명령이다. 출력 없이 대입하려고 붙였다. 콜론 내장 명령 (새 탭에서 열림)

첫 비교의 -u는 set -u와 같다. 기본값 확장은 이 옵션에서도 미설정 변수에 사용할 수 있었다. 별도 실행에서 미설정 변수를 그대로 펼치면 unbound variable 오류와 종료 코드 1이 나왔지만, 빈 문자열은 오류 없이 펼쳐졌다. set -u는 빈 값의 유효성 검사를 대신하지 않는다. nounset 조건 (새 탭에서 열림)

큰따옴표도 유지한다. 별도 인자 수 비교에서 공백을 포함한 값 red blue 는 기본 IFS 조건에서 인용하지 않으면 두 인자, 인용하면 양끝 공백을 보존한 한 인자가 됐다. 또 공백 세 개는 길이 3인 값이므로 :-와 := 모두 기본값으로 바꾸지 않았다. 수정 뒤에도 공백만 전달된다면 입력을 만드는 쪽을 확인하고, 공백만 있는 값을 허용할지는 별도로 정한다. 단어 분리 규칙 (새 탭에서 열림)

위 출력은 WSL2의 Ubuntu 24.04.4 LTS, Bash 5.2.21에서 직접 확인했다. 문서 설명은 Bash 유지관리자가 제공하는 GNU Bash 5.3 매뉴얼을 읽어 대조했다. 실험은 일반 문자열 변수와 리터럴 기본값을 대상으로 했으며, 다른 셸·배열·읽기 전용 변수나 기본값 안에서 실행하는 명령의 동작은 검증하지 않았다.

← 전체 글 보기