복제되는 GPG_TTY와 숨겨진 .zprofile 원인에 대한 궁금한 사건 (그리고 내 터미널이 왜 이렇게 느렸는가!)
Source: Dev.to

가끔씩, 겉보기에 사소한 설정 꼬임이 도트파일 세계에서는 머리를 쥐어뜯게 하는 미스터리로 변할 수 있습니다. 저는 최근에 이런 곤경에 처했는데, 바로 다음 라인입니다
export GPG_TTY=$(tty)
이 라인이 새 터미널을 열 때마다 제 .zshrc 파일에 마법처럼 다시 나타났습니다. 사소한 짜증으로 시작했지만, 곧 쉘 시작 로직, Oh My Zsh 플러그인, 그리고 종종 간과되는 도트파일 관리의 미묘한 차이점들을 파고드는 흥미로운 탐구로 이어졌고, 결국 터미널 시작 속도에 큰 성능 저하를 초래하게 되었습니다.
문제: 답답할 정도로 느린 시작 (그리고 .zshrc에 숨겨진 거대한 비밀)
터미널이 시작하는 데 영원히 걸린다는 미묘하고 점점 고통스러운 깨달음으로 시작되었습니다. 한때 즉시 뜨던 팝‑업이 이제는 몇 초씩 끈질기게 느려졌습니다. Cursor, Terminal.app, Tabby를 열고 그냥… 기다리기만 했습니다.
며칠간의 좌절 끝에 .zshrc 파일을 열어 보았습니다. 충격적으로도 그 안에는 수천 개의 동일한 라인이 포함되어 있었습니다:
export GPG_TTY=$(tty)
그 중복된 라인 하나하나가 새로운 터미널 세션을 열 때마다 Zsh에 의해 파싱되고 실행되어, 빠르던 시작을 답답한 대기 시간으로 바꾸어 놓았습니다.
GPG_TTY 환경 변수는 GnuPG (GPG)가 패스프레이즈 프롬프트에 사용할 터미널을 알게 해 주는 중요한 변수이며, Git 커밋 서명에 필수적입니다. 따라서 라인 자체는 중요하지만, (최소 3 000번이나!) 끊임없이 복제되는 것은 분명히 문제가 됩니다.
초기 의심: Oh My Zsh 플러그인
많은 Zsh 사용자들처럼 나도 처음에는 Oh My Zsh와 그 방대한 플러그인들로 바로 눈을 돌렸다. gpg-agent 플러그인이 있다는 것을 알고 있었고, 그 README.md에는 다음과 같이 명시되어 있었다:
“각 셸 실행 전에
GPG_TTY환경 변수를 업데이트합니다.”
빠른 grep을 통해 플러그인에 export GPG_TTY=$TTY 라인이 포함되어 있음을 확인했다. 이는 플러그인이 실제로 변수를 관리하고 있다는 증거였다. 처음에 나는 플러그인에 결함이 있어 .zshrc에 계속해서 쓰고 있을 것이라고 생각했다. 하지만 플러그인은 보통 소스되는 것이지, 사용자의 메인 설정 파일에 다시 쓰도록 설계되지 않는다. 이것은 중요한 구분점이다.
플러그인이 변수를 설정하고 있는데, 동시에 추가된 형태로 .zshrc에서도 보인다면, 이는 충돌을 의미한다: 플러그인은 제 역할을 하고 있지만, 다른 무언가가 중복된 라인을 작성하고 있는 것이다.
작가를 찾는 여정
라인이 작성되고 있다는 사실(단순히 소스된 것이 아님)을 아는 것이 핵심이었습니다. 저는 체계적으로 다음을 시도했습니다:
| 동작 | 결과 |
|---|---|
.zshrc에서 중복된 라인을 제거 | 다시 나타남 |
gpg-agent 플러그인 비활성화 | 라인이 여전히 다시 나타남 |
.zshrc에서 source $ZSH/oh-my-zsh.sh를 주석 처리 (Oh My Zsh 완전 비활성화) | 라인이 여전히 다시 나타남 |
이를 통해 원인이 Oh My Zsh의 직접적인 영향 바깥에 있음을 확인했으며, 이는 다른 Zsh 시작 파일이나 시스템‑레벨 스크립트에 있을 가능성이 높다는 뜻입니다.
Zsh는 특정 순서대로 여러 시작 파일을 처리합니다:
~/.zshenv~/.zprofile(로그인 셸)~/.zshrc(대화형 셸)~/.zlogin(로그인 셸,.zshrc이후)
로그인 셸 동작을 고려하면, .zprofile이 주요 용의자가 되었습니다.
The Aha! Moment: .zprofile Reveals Its Secrets
Opening my ~/.zprofile file, I immediately spotted it:
# https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key
# Add GPG key
if [ -r ~/.zshrc ]; then
echo -e '\nexport GPG_TTY=$(tty)' >> ~/.zshrc
else
echo -e '\nexport GPG_TTY=$(tty)' >> ~/.zprofile
fi
거기에 있었다—GitHub의 커밋 서명 검증 관리 문서에서 직접 가져온 듯한 스크립트로, export GPG_TTY=$(tty) 를 내 .zshrc에 추가하도록 설계된 것이었다.
여기서 내 실수를 인정해야 한다. 문서를 다시 살펴보니 이 명령은 설정을 초기화하기 위해 한 번 터미널에서 실행하도록 되어 있었다. 그런데 나는 그 로직을 잘못 복사해서 바로 ~/.zprofile에 붙여넣어 버렸다.
치명적인 결함: 스크립트에 멱등성(idempotence) 이 없었다. ~/.zshrc에 GPG_TTY가 이미 존재하는지 확인하는 절차가 전혀 없었다. 로그인 쉘이 시작되어 .zprofile을 소스할 때마다, 스크립트는 .zshrc가 읽을 수 있는지(항상 읽을 수 있음) 확인하고 조건 없이 해당 라인을 추가했다. .zprofile은 매 로그인 세션마다 실행되기 때문에, IDE를 열거나 로그인할 때마다 내 .zshrc가 새로운 export 라인으로 “스팸”되는 결과가 발생했다.
해결 방법 및 교훈
- 중복 삭제 –
~/.zshrc로 돌아가서 중복된export GPG_TTY=$(tty)라인 수천 개를 수동으로 제거했습니다. - 문제 블록 제거 –
~/.zprofile에서 전체if … else … fi블록을 삭제했습니다.
그 후 새 터미널을 열었을 때 .zshrc는 그대로 깨끗했고, GPG_TTY는 여전히 올바르게 설정되어 있었으며(Oh My Zsh gpg-agent 플러그인 덕분), 가장 중요한 것은 터미널 시작 속도가 다시 빠르게 돌아왔습니다!
주요 교훈
- 점증성은 dotfiles에서 가장 중요합니다. 설정 파일을 수정하는 모든 스크립트는 먼저 변경이 실제로 필요한지 확인해야 합니다. 이를 하지 않으면 불필요한 부피 증가, 혼란, 그리고 심각한 성능 저하를 초래합니다.
- 쉘의 시작 파일들을 이해하세요.
.zshenv,.zprofile,.zshrc,.zlogin등 파일들의 순서와 목적을 아는 것은 효율적인 dotfile 관리에 필수적입니다. - 전체 명령 스니펫을 시작 파일에 복사·붙여넣기 하지 마세요. 문서에는 일회성 명령이 종종 나와 있지만, 이를 반복 실행되는 파일에 삽입한다면 반복 실행에 안전하도록 로직을 조정해야 합니다.
이러한 교훈을 염두에 두면, 내 터미널은 다시 빠르게 동작하고 dotfiles는 깔끔해집니다—다음 미스터리가 나타날 때까지!
Troubleshooting
Third‑party documentation can be a double‑edged sword: while GitHub’s guide is intended to be helpful, the specific script provided for Zsh users could lead to issues if executed more than once, especially if it’s placed in a file like .zprofile that runs frequently.
전문 도구를 신뢰하세요: If you’re using a plugin (like Oh My Zsh’s gpg-agent) designed to manage a specific environment variable, it’s often best to let it handle the heavy lifting.
This little adventure taught me a lot about the intricacies of my own shell environment. While it was a frustrating few days, the satisfaction of finally solving the mystery and reclaiming my fast terminal startup was well worth it. Keep your dotfiles clean, and always be wary of scripts that append without checking!