환경 변수는 과거의 혼란 그 자체: 깊이 파헤쳐 보기

3 weeks ago 12

  • 소프트웨어 개발에서 환경 변수는 매우 오래된 방식임
  • 환경 변수는 부모 프로세스에서 자식 프로세스로 상속되는 구조를 가짐
  • Linux에서는 execve 시스템 콜을 통해 환경 변수가 전달됨
  • Bash, glibc, Python 등은 환경 변수를 각각 다르게 내부적으로 저장 및 처리
  • 이름 규칙 등은 느슨하지만, POSIX 표준 에서 지켜야 할 최소한의 규정이 존재함

환경 변수란 무엇인가

프로그래밍 언어는 빠르게 발전했음에도 운영체제가 제공하는 프로세스 실행 기반 구조, 특히 환경 변수 부분은 변화가 거의 없는 상태임

애플리케이션 실행 시 별도 파일이나 IPC 없이 런타임 파라미터를 전달하려면, 환경 변수 기반 인터페이스를 쓸 수밖에 없는 현실임
환경 변수는 네임스페이스도 없고, 타입도 없는, 플랫한 문자열 딕셔너리 역할을 함

환경 변수 생성 및 전달 구조

  • 환경 변수는 부모 프로세스에서 자식 프로세스로 상속되는 구조임
  • Linux에서는 execve 시스템 콜이 실행 파일, 인자, 그리고 환경 변수 배열(envp)을 인자로 받음
    • 실행 명령 예시: ls -lah라면
      • filename: /usr/bin/ls
      • argv: ['ls', '-lah']
      • envp: ['PATH=...','USER=...']
  • 거의 모든 도구(Bash, Python의 subprocess.run, C 라이브러리 execl 등)는 환경 변수를 그대로 넘겨줌
  • 예외적으로, login과 같은 일부 도구는 새로운 환경을 구성함

환경 변수의 저장 위치와 내부 처리

  • 커널은 환경 변수들을 스택에 null-terminated string 형태로 저장함
  • 각 언어 및 쉘의 환경 변수 저장 방식
    • Bash: 스택 구조의 해시맵(딕셔너리)로 관리
      • 함수 호출마다 로컬 스코프의 맵 생성
      • export된 변수만 자식 프로세스에 전달
      • 로컬 변수도 export 가능함
    • glibc(C 라이브러리) : 동적 배열 구조의 environ을 putenv, getenv를 통해 관리
      • 배열 구조라 조회/변경 모두 선형 시간 복잡도를 가짐
    • Python: 내부에서 os.environ으로 딕셔너리처럼 제공하나, 실상은 C 라이브러리의 environ 배열과 연동
      • os.environ 값 변경 시 os.putenv 호출되어 C라이브러리에도 반영
      • 반대 방향은 동기화되지 않으므로 일방향성 존재

환경 변수의 포맷과 허용 범위

  • Linux 커널과 glibc는 환경 변수 포맷에 매우 관대
    • 동일 이름이 중복되어 여러 값이 존재 가능
    • = 없이도 등록 가능하고, 이모지 등 특수문자도 제한 없음
  • 가용 사이즈 제한
    • 개별 변수: 128 KiB (보통 x64 환경)
    • 전체 합계: 2 MiB (명령행 인자와 공유)
      • 이는 초기 환경 변수가 스택에 저장됨에 따라 제한 설정

환경 변수의 특이점 및 에지 케이스

  • Bash는 이상한 환경 변수(중복, = 없는 항목 등)는 dedup 및 무시
  • 변수 이름에 공백이 있으면 Bash는 이름 참조 불가하나, 여전히 자식 프로세스에 전달 가능
    • 예: Nushell, Python 등은 공백 이름 변수 생성 가능
    • Bash는 이런 항목을 별도 해시맵(invalid_env)에 저장하여 관리

표준(standard) 환경 변수 포맷 및 이름 규칙

  • POSIX 표준은 이름에 등호(=)만 없으면 변수로 인정
    • 공식 권장: 이름은 대문자, 숫자, 언더스코어만 허용(맨 앞은 숫자 불가)
    • 소문자 변수는 애플리케이션 전용 네임스페이스용 용도
    • 표준 도구는 대문자만 사용하지만, 소문자 변수 사용도 허용
  • 실제로는 개발자들이 ALL_UPPERCASE 방식으로 주로 네이밍

실용적 권장 사항

  • 변수 이름은 정규식 ^[A-Z_][A-Z0-9_]*$ 사용, 값은 UTF-8
  • 예외나 호환성 걱정 시 POSIX의 Portable Character Set(ASCII) 사용 권장

결론 및 마무리

  • 환경 변수 구조와 실제 동작에 대해 파헤치는 경험 자체가 독특하고 즐거움

Read Entire Article