환경 변수와 실행 위치
55분 안팎
학습 목표
작업 경로와 PATH 변경에 따른 명령 탐색 결과를 비교하고 비밀값 없이 환경 차이를 기록합니다.
개념
같은 명령이 다른 곳에서 실패합니다
터미널에서 실행한 도구가 다른 폴더나 자동 실행 환경에서는 실패하는 일이 있습니다. 시스템 담당자는 재설치부터 하기보다 실행 위치, 명령 탐색 경로, 전달한 변수를 비교합니다. 이번 레슨은 설정을 자기 파일 옆에서 읽는 작은 셸 도구를 만듭니다. 호출자의 현재 디렉터리와 상관없이 설정을 읽고, 필요한 환경 값과 python3의 탐색 결과만 출력하게 합니다.
프로세스에는 현재 작업 디렉터리와 환경 변수라는 실행 맥락이 있습니다. 상대 경로로 파일을 여는 동작은 작업 디렉터리에 영향을 받고, 이름만으로 실행 파일을 찾는 동작은 PATH에 영향을 받습니다. 환경 변수 LAB_LABEL은 작업 이름을 전달합니다. 이 세 요소를 따로 바꾸며 실험하면 설정 파일 없음과 명령 없음, 변수 미전달을 같은 문제로 뭉뚱그리지 않을 수 있습니다.
환경 변수에 모든 설정을 넣는 것이 목적은 아닙니다. 이번 예제는 비밀이 아닌 실습 이름 하나만 전달하고 설정 파일에는 lab-web이라는 고정 이름을 둡니다. 출력도 label, config, python 세 항목으로 제한합니다. 환경 전체를 env로 출력하면 다른 작업의 토큰이나 개인 경로가 섞일 수 있습니다. 인계할 정보는 필요한 키만 선택하고 민감한 값이 있다면 공유 기록에서 제거합니다.
셸 변수와 환경 변수를 구분합니다
LAB_LABEL=day처럼 값을 지정하면 현재 셸에서 변수를 사용할 수 있습니다. 새 자식 셸이 그 값을 받게 하려면 export로 환경에 포함해야 합니다. 이미 환경에 포함된 변수인지에 따라 동작이 달라질 수 있어 실험에서는 unset으로 초기 상태를 정합니다. 단지 현재 셸에서 printf가 값을 보여 준다는 사실은 자식 프로그램도 받았다는 증거가 아닙니다.
export LAB_LABEL 뒤에 시작한 자식은 값을 받을 수 있지만 자식이 변수를 바꿔도 부모 셸 값이 자동으로 바뀌지 않습니다. 프로세스를 실행할 때 전달하는 복사된 맥락으로 이해하면 됩니다. env LAB_LABEL=night 명령은 그 실행에 사용할 값을 지정하는 방식입니다. 터미널 세션 전체를 바꾸지 않고 차이를 비교할 수 있어 이번 따라하기에서도 사용합니다.
변수 미설정과 빈 문자열은 요구사항에 따라 다른 의미일 수 있습니다. ${LAB_LABEL:-training}은 미설정 또는 빈 값에 기본값을 사용합니다. ${LAB_LABEL-training}은 미설정에만 기본값을 쓰고 빈 값은 남깁니다. 이번 도구는 둘 다 training으로 취급하므로 콜론이 있는 형태를 선택합니다. 기본값을 정했다는 사실을 README에 적어 호출자가 빈 값의 의미를 오해하지 않게 합니다.
PATH는 실행 파일 탐색 순서입니다
PATH에는 실행 파일을 찾을 디렉터리를 콜론으로 구분해 넣습니다. python3처럼 슬래시 없는 명령 이름은 셸의 명령 탐색 규칙을 거칩니다. command -v python3는 현재 셸이 탐색한 위치나 명령 정보를 보여 줍니다. 버전이 맞는지까지 보장하는 검사는 아니므로 실행 가능한지와 필요한 버전 확인은 별도 관찰입니다. 이번 도구는 탐색 결과를 기록하는 데 집중합니다.
PATH 앞쪽에 다른 실행 파일이 있으면 같은 이름으로 다른 구현을 선택할 수 있습니다. 현재 폴더를 뜻하는 .을 PATH에 무심코 넣으면 다운로드한 폴더의 동명 파일이 선택될 수 있습니다. ./task.sh처럼 경로를 명시하면 PATH에서 그 파일을 찾지 않지만 실행 권한과 인터프리터 조건은 여전히 필요합니다. 이 실습은 bash task.sh로 실행하여 실행 비트 유무에 따라 안내가 갈리지 않게 합니다.
PATH를 텅 빈 값으로 바꾸면 외부 도구를 찾지 못할 수 있습니다. 셸 자체의 내장 명령인 printf가 된다고 cat도 된다는 보장은 없습니다. 따라하기에서는 /usr/bin:/bin처럼 필수 시스템 도구가 있는 경로를 명시하고 변경은 하위 셸에만 적용합니다. 전역 설정 파일을 수정하지 않아 실험 뒤 기존 작업 환경을 복구하는 별도 조치가 필요 없게 합니다.
설정 경로는 도구 위치에서 시작합니다
cat config/name.txt는 호출자가 서 있는 위치 아래에서 파일을 찾습니다. 도구를 다른 폴더에서 호출하면 설정이 사라진 것처럼 보일 수 있습니다. Bash 스크립트의 $0는 호출한 스크립트 경로이며 dirname으로 그 디렉터리를 얻을 수 있습니다. 그 폴더로 이동한 하위 셸에서 pwd -P를 실행해 base를 만들고 "$base/config/name.txt"를 읽으면 현재 작업 위치와 분리할 수 있습니다.
base=$(cd -- "$(dirname -- "$0")" && pwd -P)에서 cd와 pwd는 명령 치환 안의 하위 셸에서 실행됩니다. 부모 스크립트의 작업 디렉터리를 바꾸지 않고 기준 경로만 얻습니다. cd가 실패하면 pwd를 진행하지 않도록 &&로 연결합니다. 공백이 있는 도구 폴더에서 dirname 결과와 base를 각각 인용하는 것도 필요합니다. 한 부분만 인용하면 나머지 경로 확장에서 문제가 남을 수 있습니다.
이 방식은 일반 파일로 내려받아 bash 경로/task.sh로 호출하는 조건에 맞습니다. 심볼릭 링크를 통해 다른 위치의 스크립트를 호출하면 링크 위치와 실제 파일 위치 중 무엇을 기준으로 할지 정책이 필요합니다. 이번 실습 ZIP은 심볼릭 링크를 쓰지 않습니다. 범위를 적고 검증한 조건을 유지하면 특정 경로 처리법을 모든 배포 형태의 정답으로 확대하는 일을 피할 수 있습니다.
관측 정보를 최소한으로 전달합니다
도구 출력은 label=작업 이름, config=lab-web, python=탐색 경로 세 줄입니다. 순서는 고정하며 python 값 자체는 설치 위치에 따라 달라집니다. 검사기는 현재 Python 3 위치를 알아낸 뒤 그 경로와 비교하므로 학습자의 설치 경로를 예제 숫자처럼 고정하지 않습니다. LABEL이 night shift처럼 공백을 포함해도 한 줄의 값으로 유지되어야 합니다.
실습 검사는 도구 폴더를 공백이 있는 임시 위치로 복사하고 바깥 폴더에서 실행합니다. 명시한 LAB_LABEL이 전달되는지, 미설정에서는 training이 되는지, 설정 파일은 자기 위치에서 읽는지 확인합니다. 체크를 통과했다고 서비스 관리자에서도 같은 PATH가 적용된다고 말하지 않습니다. 이후 systemd 모듈에서 서비스 환경을 명시하고 실제 프로세스와 로그로 다시 확인합니다.
command not found가 나오면 실패한 이름과 PATH의 관련 부분을 확인합니다. No such file or directory가 config/name.txt에 대해 나오면 호출 위치 의존성을 살핍니다. label이 기대한 값과 다르면 export 여부와 빈 값 규칙을 확인합니다. 단일 실패 화면에서도 이 세 질문을 구분하면 조사 순서를 정할 수 있습니다. 에러를 숨겨 통과시키기보다 관측 차이를 작게 재현합니다.
자동 실행을 준비하는 습관을 만듭니다
인계 문서에는 실행 파일 위치와 명령, 필요한 환경 이름, 기본값, 설정 경로 기준을 적습니다. 비밀값을 쓰지 않는 이 실습에서도 환경 전체를 덤프하지 않는 습관을 연습합니다. 더 읽기의 env 장에서 환경 도구를 확장하고, 미션에서는 지금 만든 경로·입출력·환경 확인을 묶습니다. 파일 작업이 성공한 증거와 VM에서 수행했다는 증거를 함께 남겨 다음 계정 모듈의 출발 상태를 명확하게 합니다.
따라하기
자식에게 전달되는 값
새 Bash에서 실행합니다. 변수를 내보내기 전후에 자식의 기본값이 달라집니다.
unset LAB_LABEL
LAB_LABEL=day
bash -c 'printf "before=%s
" "${LAB_LABEL:-unset}"'
export LAB_LABEL
bash -c 'printf "after=%s
" "$LAB_LABEL"'실행 결과
before=unset after=day
실행 한정 값 비교
env는 자식 실행에 값을 전달합니다. 부모 값은 이 실험에서 그대로 남습니다.
export LAB_LABEL=day
env LAB_LABEL=night bash -c 'printf "child=%s
" "$LAB_LABEL"'
printf "parent=%s
" "$LAB_LABEL"실행 결과
child=night parent=day
다른 위치의 설정 읽기
자기 위치를 기준으로 읽는 스크립트를 만들어 바깥 폴더에서 실행합니다. 모범 구현과 같은 경로 구성 방식을 비교합니다.
mkdir -p "tool folder/config"
printf "lab-web
" > "tool folder/config/name.txt"
cat > "tool folder/task.sh" <<'END'
base=$(cd -- "$(dirname -- "$0")" && pwd -P)
printf "config=%s
" "$(cat "$base/config/name.txt")"
END
bash "tool folder/task.sh"실행 결과
config=lab-web
명령 탐색 차이
외부 명령을 찾을 수 없는 PATH를 하위 셸에만 줍니다. command와 printf는 Bash 내장 명령입니다.
/bin/bash -c 'PATH=/nonexistent; if command -v python3; then printf "found
"; else printf "python=not-found
"; fi'실행 결과
python=not-found
확인 문제
실습
task.sh가 다른 현재 디렉터리에서도 자기 설정을 읽게 합니다. LAB_LABEL 기본값과 공백 값을 처리하고 python3 탐색 위치를 출력합니다.
실행 명령
bash check.sh
기대 결과
PASS environment: outside cwd, default, spaced label
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 점검 스크립트가 실패를 알리는 방식을 설명합니다.