환경변수로 둔 CLI 기본값: 비대화형 셸에서 사라지는 이유
문서를 저장하는 CLI를 하나 만들었습니다. 저장할 때마다 그 문서가 어디로 떨어졌는지 찾는 일이 반복돼서, 새 문서는 인박스로 가도록 기본값을 정했습니다. 터미널에서 쳐 보니 의도한 자리에 들어갔습니다.
그런데 같은 명령을 코딩 에이전트가 대신 부르자, 문서가 폴더 없이 저장됐습니다. 명령도 같고 인자도 같은데 결과만 달랐습니다.
원인은 셸 설정에 둔 기본값
저는 폴더 이름을 스크립트에 박고 싶지 않았습니다. 폴더를 바꿀 때마다 코드를 고치는 건 설정이 아니라 하드코딩이니까요. 그래서 셸 설정 조각에 환경변수로 뒀습니다.
# ~/.config/zsh/30-env.zsh
export SYSDOC_FOLDER="인박스"스크립트는 ${SYSDOC_FOLDER:-} 를 읽고, 값이 있으면 그 폴더로 보냅니다. 제 터미널에서는 완벽하게 동작했습니다. 새 셸을 띄워 확인까지 했습니다.
문제는 제 터미널만 그 파일을 읽는다는 것이었습니다.
셸마다 다르게 읽는 설정 파일
zsh는 어떤 방식으로 뜨느냐에 따라 읽는 파일이 갈립니다.
| 부르는 자리 | 셸의 종류 | 읽는 파일 |
|---|---|---|
| 터미널에서 직접 | 대화형 로그인 | .zprofile, .zshrc |
| 스크립트 안에서 | 비대화형 | 둘 다 안 읽습니다 |
| 에디터·에이전트가 실행 | 비대화형(대개 bash) | .zshrc 는 애초에 zsh 것입니다 |
제 기본값은 .zshrc 가 읽어 들이는 조각에 있었습니다. 그러니 사람이 치면 있고, 무언가가 대신 부르면 없습니다. 도구를 자동화에 쓰라고 만들어 놓고, 자동화에서만 기본값이 빠지는 구조를 제가 직접 만든 셈입니다.
이 실패가 나쁜 이유는 조용해서입니다. 에러가 나지 않습니다. 문서는 저장되고, 명령은 0으로 끝나고, 폴더만 비어 있습니다. 저는 저장 결과를 눈으로 보고 나서야 알았습니다.
셸을 거치지 않는 설정 파일
고친 방법은 단순합니다. 기본값을 셸에서 파일로 옮겼습니다.
# ~/.config/desk/sysdoc.conf
folder=인박스스크립트가 이 파일을 직접 읽습니다. bash로 부르든 zsh로 부르든, 로그인 셸이든 아니든 같은 값이 나옵니다. 우선순위는 명령행 옵션, 환경변수, 설정 파일 순으로 뒀습니다. 급할 때 환경변수로 덮어쓰는 길은 남겨 두되, 기본값이 거기 있지는 않게 한 것입니다.
확인은 환경변수를 지운 채로 했습니다.
env -u SYSDOC_FOLDER bash -c 'sysdoc save --title … -n'-n 은 실제로 쓰지 않고 만들어질 SQL만 보여주는 옵션입니다. 여기서 폴더 ID가 제대로 박혀 나오는 것을 보고서야 고쳐졌다고 판단했습니다. 처음에는 이 확인용 옵션이 폴더를 해석하지 않고 항상 NULL을 보여줬는데, 그건 확인용 옵션이 거짓말을 하는 것이라 같이 고쳤습니다.
기본값이 갱신 때 만드는 문제
고치고 나서 다른 문제가 보였습니다. 기본 폴더가 저장 명령 전체에 걸리면, 이미 정리해 둔 문서를 다시 저장할 때마다 그 문서가 인박스로 되돌아갑니다. 사람이 폴더를 옮겨 정리해 놓아도 다음 저장 한 번에 지워집니다.
그래서 기본값은 새 문서에만 적용하고, 기존 문서를 갱신할 때는 폴더를 건드리지 않게 했습니다. 옮기려면 --folder 를 직접 줘야 합니다. 기본값과 명시적 지정을 같은 변수로 다루면 이 구분이 안 생깁니다. 스크립트 안에서 "사용자가 직접 준 값인가" 를 따로 기억하게 만들어야 했습니다.
남은 것
지금 구조에서도 설정 파일의 경로 자체는 여전히 환경변수로 바꿀 수 있습니다. 그 변수는 같은 함정을 그대로 갖고 있습니다. 다만 그건 평소에 쓰는 길이 아니라 시험용 우회로라 남겨 뒀습니다.
교훈을 한 줄로 적자면, 설정을 셸에 묶으면 그 설정은 사람이 부를 때만 존재합니다. 도구를 사람만 부를 것이라고 가정할 수 있는지 먼저 물어봐야 하고, 요즘은 그렇게 가정할 수 없는 경우가 늘고 있습니다.
함께 읽기
- colima 자동 기동: brew services가 10초마다 재실행되는 이유개발기에 도커를 새로 깔 일이 생겼습니다. 컨테이너 하나만 돌리면 되는 일이라 가볍게 끝날 줄 알았는데, 설치 자체는 5분이었고 그 뒤에 두 가지를 더 고쳐야 했습니다. 하나는 깃 저장소가 더러워진 것이고, 하나는 코어 하나의 2.8%가 계속 타고 있던 것입니다.
- 드라이런과 멱등성: 사고를 막는 시점의 차이배포 스크립트에 안전장치를 넣는다고 할 때 두 가지가 자주 같이 나옵니다.
- 새 맥북 개발 환경 세팅: git clone이 가져오지 않는 것들맥북을 새로 받고 하던 프로젝트를 이어서 하려 했습니다. 리포를 클론하고 npm install 을 돌린 다음 개발 서버를 띄웠는데, 브라우저에 이게 떴습니다.
- xcode-select와 DEVELOPER_DIR: 어느 쪽이 정석일까?Expo 앱을 iOS 시뮬레이터에 띄우려고 도구부터 점검했는데, 결과가 앞뒤가 안 맞았습니다.
- prisma generate 를 어디서 돌릴까: postinstall 과 도커 빌드 캐시새 맥에 프로젝트들을 하나씩 세우는 중이었습니다. 클론하고, 의존성을 깔고, 개발 서버를 띄우면 이 화면이 떴습니다.