쉘 스크립트 자동화에서 stderr 출력 누락 버그를 잡다
목차
최근 codex 인증 체크 스크립트를 보다가 로그인 상태 명령이 예상과 다르게 동작하는 걸 발견했다. 문제는 간단했지만, 그 과정에서 배운 게 꽤 있어서 정리해본다.
문제: 명령어 출력이 사라지다
codex-auth-check.sh 스크립트에서 login status를 확인하는 부분이 있었는데, 해당 명령어가 실행된 후 출력값을 변수에 담으려는 로직이 제대로 작동하지 않았다. 처음엔 명령 자체가 실패했다고 생각했지만, 실제로는 명령이 성공했고 출력도 있었다. 다만 그 출력이 stderr로 나가고 있었다.
shell에서 var=$(command) 형태로 실행할 때 기본적으로 stdout만 변수에 담긴다. 애플리케이션이나 시스템 명령이 정상적으로 동작하면서도 진단/상태 정보를 stderr로 보내는 경우가 꽤 흔하다. 이번 codex login status도 그런 케이스였던 것 같다. 결과적으로 필요한 정보가 터미널에만 찍히고 스크립트 흐름에 전달되지 않았던 거다.
해결: 2>&1로 통합 캡처
해결 방법은 간단하다. 커밋 메시지 그대로 2>&1 리다이렉션을 추가해서 stderr도 stdout과 함께 캡처하는 것이다.
# Before
status=$(codex login status)
# After
status=$(codex login status 2>&1)
이렇게 하면 두 스트림이 합쳐져서 변수 status에 담기게 된다. 보통 이런 상황은 두 가지 시나리오에서 발생한다:
| 상황 | 원인 | 처리 방법 |
|---|---|---|
| 명령이 성공하지만 상태/진단정보가 stderr | 설계상 정상 동작 | 2>&1 로 통합 |
| 명령이 실패하고 에러가 stderr | 에러 처리 필요 | stderr만 별도 캡처 후 처리 |
| 둘 다 필요한 경우 | 출력과 에러 동시 분석 | 각각 임시 파일로 리다이렉트 |
이번 케이스는 첫 번째 시나리오였다. codex 명령이 정상 작동하면서도 login status 정보를 stderr로 내보내는 거였다.
왜 이런 일이 발생할까?
여러 경험상, 이런 류 버그는 다음 단계에서 나타난다:
- 초기 개발 단계: 스크립트는 특정 환경(로컬 개발 머신)에서만 테스트됨
- 모니터링/자동화 도입: 서버나 CI에서 같은 스크립트 실행 → 동작이 달라짐
- 외부 커맨드 업데이트: 내가 짠 게 아닌 외부 도구의 출력 형식 변경
- 리다이렉션 누락: stdout만 캡처하는 게 습관화됨
특히 팀 차원에서는 다른 사람이 작성한 스크립트를 받았을 때 이런 일이 자주 생긴다. 원래 작성자는 수동으로 명령어를 실행했을 때는 에러 메시지를 화면에서 봤으니까 문제 없다고 생각했는데, 자동화 환경에서는 stderr가 어딘가로 사라지는 경우다.
이전 경험과 패턴화
과거에 비슷한 상황을 여러 번 봤다:
- 토큰 검증 로직에서 에러 메시지를 stderr로 내보내는 API 클라이언트
- 데이터베이스 연결 상태를 확인하는 헬스체크 스크립트
- 환경 변수 검증 유틸리티
대부분 "정상 동작하는데 출력이 누락됨" 패턴이었다. 요즘은 이런 스크립트를 짤 때 최대한 빨리 stderr 리다이렉션을 고려한다.
회고: 작은 핀포인트, 큰 교훈
이 커밋은 라인 수로 보면 정말 작은 수정이다. 2>&1 네 글자를 추가했을 뿐이다. 하지만 이걸 통해 느낀 건 자동화 스크립트의 출력 처리가 생각보다 중요하다는 것. 수동 실행과 자동화된 실행의 환경이 다르면, 단순한 리다이렉션 누락도 사일로(silo)를 만들 수 있다.
팀에서 이런 류 버그를 줄이려면:
- 쉘 스크립트 템플릿: 기본적으로 set -e, set -o pipefail 같은 안전 옵션 포함
- 코드리뷰 체크리스트: 외부 명령어 실행 시 출력 캡처 여부 확인
- 로컬 vs CI 테스트: 같은 스크립트를 두 환경에서 검증
이번 fix는 "작지만 필요한 변경"이었고, 앞으로도 이런 자잘한 함정에 먼저 주의하려고 한다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.