.env 에서 값을 뽑는 sed 스크립트를 만들었더니 어떤 값은 빈 문자열로 나왔다. 따옴표가 있는 항목만 뽑히고 없는 항목은 패턴이 안 맞아 그대로 빠지고 있었다.
Table of contents
Open Table of contents
원인 — 따옴표 유무가 가른 결과
정규식이 KEY="value" 형태를 전제하고 있어서 KEY=value 에서는 치환이 일어나지 않았다. cut -d= -f2- 로 잘라 가져온 뒤에 따옴표만 벗기는 방식으로 바꿔 두 형태를 모두 받게 했다.
있으면 벗기고 없으면 그대로 두는 것이므로 형식에 의존하지 않는다. 형식을 전제한 패턴은 그 전제를 벗어난 입력에서 오류가 아니라 빈 값을 낸다.
주의 — 빈 값이 기본값으로 동작하는 위험
더 위험한 것은 못 뽑았을 때 조용히 빈 문자열이 되는 쪽이었다. 그 값이 DB_HOST 로 쓰이면 빈 값이 곧 localhost 를 뜻하게 되어 의도한 대상과 다른 곳에 붙는다.
실제로 운영 데이터베이스에 붙으려다 로컬에 붙은 적이 있었다. 그래서 항목이 없으면 빈 값이 아니라 exit 1 로 끝내고 메시지를 stderr 로 내게 했다.
조치 — 셸에 맡기는 방법의 대가
두 가지 방법이 있었는데 source .env 로 셸이 파일을 직접 읽게 하는 것과 줄 단위로 직접 파싱하는 것이다. 앞쪽은 따옴표든 아니든 전부 처리되므로 파싱을 안 해도 된다. 다만 파일 안에 $(...) 명령 치환이 들어 있으면 그것도 같이 실행된다.
내가 만든 파일이면 괜찮지만 밖에서 오는 파일에는 쓸 수 없는 방법이다. 뒤쪽을 골랐다. 이유는 이 스크립트가 받을 파일의 출처를 통제할 수 없어서다. 대신 따옴표와 주석과 중복 키를 직접 다뤄야 하는 것을 감수했다.
검증 — 주석과 중복 키
주석 처리된 옛 값이 위에 남아 있으면 그것이 먼저 잡히는 문제가 있었다. ^KEY= 로 줄 앞에서 시작하는 것만 잡게 하니 # 으로 시작하는 줄은 걸리지 않았다.
같은 키가 여러 번 있는 경우는 더 미묘한데 첫 번째를 쓸지 마지막을 쓸지가 읽는 쪽마다 다르다. 읽는 쪽과 다른 쪽을 고르면 스크립트가 뽑은 값과 프로그램이 쓰는 값이 갈리므로 중복이 있으면 알리게 했다.
배경 — 값에 섞인 구분자
DB_PASSWORD 처럼 = 가 값 안에 들어가는 항목이 있었다. -f2- 로 첫 구분자에서만 자르고 나머지는 값으로 두게 해서 뒤가 잘리지 않게 했다.
주석 기호가 값에 있는 경우도 있어서 값에는 따옴표를 붙이는 규칙을 정했다. 시작할 때 필요한 항목이 전부 뽑혔는지 한 번 확인하게 하되 값 자체는 찍지 않고 앞 몇 글자만 남겼다.
정리
- 형식을 전제한 정규식은 그 전제를 벗어난 입력을 조용히 놓친다
- 구분자로 자르고 따옴표만 벗기면 두 형태를 다 받는다
- 못 뽑았을 때 빈 값이 아니라 실패로 끝낸다
- 빈 값은 접속 주소에서 기본값처럼 동작한다
- 셸이 읽게 하면 형식은 해결되지만 명령이 실행될 수 있다
- 밖에서 오는 파일은 줄 단위로 직접 파싱한다
- 주석과 중복 키를 다루고 중복이 있으면 알린다
- 확인 출력에는 값 전체가 아니라 앞 몇 글자만 남긴다