- 소프트웨어가 급격히 발전했지만, 운영체제의 환경 변수 시스템은 여전히 수십 년 전의 구조를 유지하고 있음
- 환경 변수는 전역 문자열 딕셔너리 형태로, 네임스페이스나 타입이 없는 단순한 구조를 가짐
- 리눅스에서 환경 변수는
execve시스템 호출을 통해 부모 프로세스에서 자식으로 전달됨 - Bash, glibc, Python 등은 각각 환경 변수를 해시맵, 배열, 딕셔너리 래핑 형태로 관리함
- POSIX 표준은 이름에 대문자만을 요구하지 않으며, 실제로는 소문자 이름 사용이 권장되는 등 유연한 규칙을 가짐
환경 변수란 무엇인가
- 프로그래밍 언어는 빠르게 발전했음에도 운영체제가 제공하는 프로세스 실행 기반 구조, 특히 환경 변수 부분은 변화가 거의 없는 상태임
- 애플리케이션 실행 시 별도 파일이나 IPC 없이 런타임 파라미터를 전달하려면, 환경 변수 기반 인터페이스를 쓸 수밖에 없는 현실
- 환경 변수는 네임스페이스도 없고, 타입도 없는, 플랫한 문자열 딕셔너리 역할을 함
환경 변수 생성 및 전달 구조
- 환경 변수는 프로세스 간 값을 전달하는 전통적인 방법으로, 부모 프로세스가 자식 프로세스를 실행할 때 함께 전달됨
- 즉, 부모 프로세스에서 자식 프로세스로 상속되는 구조
- Linux에서는
execve시스템 콜이 실행 파일, 인자, 그리고 환경 변수 배열(envp)을 인자로 받음- 실행 명령 예시:
ls -lah라면- filename:
/usr/bin/ls - argv:
['ls', '-lah'] - envp:
['PATH=...','USER=...']
- filename:
- 실행 명령 예시:
- 부모 프로세스는 자식에게 기존 환경을 그대로 넘길 수도 있고, 완전히 새로운 환경을 구성할 수도 있음
- 거의 모든 도구(Bash, Python의
subprocess.run, C 라이브러리execl등)는 환경 변수를 그대로 넘겨줌 - 예외적으로,
login과 같은 일부 도구는 새로운 환경을 구성함
- 거의 모든 도구(Bash, Python의
환경 변수의 저장 위치와 내부 처리
- 커널은 프로그램 시작 시 환경 변수들을 스택에 null-terminated string 형태로 저장함
- 이 데이터는 프로그램이 직접 수정하기 어렵고, 보통은 프로그램 내부에서 복사해 자체 구조로 관리함
- 각 언어 및 쉘의 환경 변수 저장 방식
-
Bash: 스택 구조의 해시맵(딕셔너리)로 관리
- 함수 호출마다 로컬 스코프의 맵 생성
-
export된 변수만 자식 프로세스에 전달 -
local로 선언된 변수도export를 통해 자식 프로세스에 전달 가능함- 예:
export PATH를 통해 로컬 변경을 자식에게 반영하지만 전역에는 영향을 주지 않음
- 예:
-
glibc(C 라이브러리) : 동적 배열 구조의
environ을putenv,getenv를 통해 관리- 배열 구조라 조회/변경 모두 선형 시간 복잡도를 가짐
- 따라서 성능 요구가 높은 데이터 저장 용도로 사용하기에는 부적합
-
Python: 내부에서
os.environ으로 딕셔너리처럼 제공하나, 실상은 C 라이브러리의environ배열과 연동됨-
os.environ값 변경 시os.putenv호출되어 C라이브러리에도 반영 - 반대 방향은 동기화되지 않으므로 단방향성 존재
-
-
Bash: 스택 구조의 해시맵(딕셔너리)로 관리
환경 변수의 포맷과 허용 범위
- Linux 커널과 glibc는 환경 변수 포맷에 매우 관대함
- 동일 이름이 중복되어 여러 값이 존재 가능
-
=없이도 등록 가능하고, 이모지 등 특수문자도 제한 없음
- 가용 사이즈 제한
- 개별 변수: 128 KiB (보통 x64 환경)
- 전체 합계: 2 MiB (명령행 인자와 공유)
- 환경 변수는 스택 공간의 1/4을 넘지 않도록 제한되어 있음
환경 변수의 특이점 및 에지 케이스
- Bash는 이상한 환경 변수(중복, = 없는 항목 등)의 경우 중복 이름 제거 및 비정상 항목 무시
- 변수 이름에 공백이 있으면 Bash는 이름 참조 불가하나, 여전히 자식 프로세스에 전달 가능
- 예: Nushell, Python 등은 공백 이름 변수 생성 가능
- Bash는 이런 항목을 별도 해시맵(
invalid_env)에 저장하여 관리
표준(standard) 환경 변수 포맷 및 이름 규칙
-
POSIX 표준은 이름에 등호(
=)만 없으면 변수로 인정- 공식 권장: 이름은 대문자, 숫자, 언더스코어만 허용(맨 앞은 숫자 불가)
- 소문자 변수는 애플리케이션 전용 네임스페이스용 용도
- 표준 도구는 대문자만 사용하지만, 소문자 변수 사용도 허용
- 실제로는 개발자들이 ALL_UPPERCASE 방식으로 주로 네이밍
- 추천 규칙: 변수 이름은 정규식
^[A-Z_][A-Z0-9_]*$사용, 값은 UTF-8 사용- 예외나 호환성 걱정 시 POSIX의 Portable Character Set(ASCII) 사용 권장
결론
- 환경 변수는 여전히 낡지만 필수적인 인터페이스로, 운영체제와 응용 프로그램의 경계면 역할을 수행함
- 구조적 한계에도 불구하고 Bash, C, Python 등은 이를 각자 다른 방식으로 래핑해 활용 중임
- 현대적 시스템에서는 명확한 네임스페이스와 타입 체계가 있는 설정 관리 방식이 점점 더 필요함