자동화 slecs

zsh와 bash 문법 불일치로 빈 파일이 생성된 문제 해결

목차

쉘 스크립트로 자동 생성하려던 파일이 빈 채로 남아 있었다.


무엇이 문제였나

zsh에서 ${SITE^^} 문법을 썼다가 빈 파일이 만들어졌다. ^^는 bash 4.x 이상에서 지원하는 대문자 변환 문법인데, zsh에서는 이 문법이 조용히 실패하거나 빈 값으로 치환돼버리는 경우가 있다. 결과적으로 admin_db.py는 0바이트짜리 껍데기로 생성됐고, 봇 초기화 흐름 어딘가에서 이 파일을 import하려다 조용히 터졌다.

이런 류의 오류가 까다로운 이유는 에러 메시지 자체는 나오지 않는다는 것이다. 파일은 분명히 존재하고, ls에도 뜨고, git에도 추가된다. 그런데 내용이 없으니 실제로 실행했을 때야 비로소 ImportError 혹은 AttributeError 같은 게 터진다. 자동화 파이프라인에서 파일 생성 단계와 실행 단계가 분리돼 있으면 더욱 늦게 발견된다.


zshbash 문법 불일치, 생각보다 자주 밟는다

문법 bash 4.x zsh
${VAR^^} (대문자 변환) ✅ 지원 ❌ 미지원 (조용히 실패 가능)
${VAR,,} (소문자 변환) ✅ 지원 ❌ 미지원
${VAR:u} (대문자 변환) ❌ 미지원 ✅ 지원
${VAR:l} (소문자 변환) ❌ 미지원 ✅ 지원

로컬 개발 환경이 macOS + zsh인 경우, CI/CD나 서버가 bash 기반이면 이 불일치가 역방향으로도 생긴다. 반대로 이번처럼 로컬에서 zsh로 스크립트 돌릴 때 bash 문법을 썼다가 빈 파일이 뚝 떨어지는 상황도 충분히 발생한다.

팀에서 자동화 스크립트를 공유할 때 #!/bin/bash 또는 #!/usr/bin/env bash를 명시하지 않으면 실행하는 사람의 기본 셸에 따라 동작이 달라진다. 이걸 컨벤션으로 못 박아두지 않으면 "내 로컬에선 됐는데"가 꼭 한 번씩 나온다.


그래서 Python으로 직접 작성했다

셸 문법 호환성 문제를 근본적으로 피하기 위해 admin_db.py 파일을 Python으로 직접 작성하는 방향으로 전환했다. 자동 생성 방식이 편리해 보여도, 생성 도구 자체가 환경에 종속되면 재현성이 깨진다. 특히 봇처럼 여러 환경(로컬, 스테이징, 서버)에서 돌아가는 컴포넌트는 코드 자체가 명시적으로 관리되는 게 낫다.

# bot/admin_db.py — 기존 자동 생성 방식 대신 명시적으로 작성
# 환경 변수 기반 대문자 변환은 Python 내부에서 처리

import os

SITE = os.environ.get("SITE", "").upper()

# 이하 admin_db 초기화 로직...

str.upper()로 해결되는 걸 셸 문법 하나 때문에 한 사이클 날린 셈이다. Python 안에서 처리하면 셸 버전, 사용자 환경, OS에 상관없이 동일하게 동작한다.


회고

자동화 스크립트가 파일을 생성할 때는 생성 후 내용 검증 단계를 넣는 게 맞다. 최소한 파일 크기가 0인지 체크하거나, 생성된 파일을 python -c "import ast; ast.parse(open('파일').read())" 수준으로라도 구문 검증해두면 이런 사고가 런타임까지 안 흘러간다.

팀원들한테도 이번 건 공유했다. "셸 스크립트가 조용히 실패할 수 있다"는 게 직접 밟아보기 전까진 잘 안 와닿는 개념이라서. 이런 자잘한 환경 불일치가 쌓이면 나중에 온보딩하는 사람이 가장 힘들다. 재현도 안 되고, 문서도 없고, 그냥 "원래 그랬어요"로 전승되는 버그가 된다.

다음


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.