본문 바로가기
빌드노트 검색

빌드노트

PATH에는 새 파일이 있는데 Bash가 지워진 경로를 실행한다

PATH에서 새 파일이 검색돼도 같은 Bash는 사라진 옛 경로를 기억할 수 있다. type과 hash로 판별하고, hash -d·hash -r·checkhash의 적용 범위를 실제 파일 이동 실험으로 비교한다.

Bash에서 실행 파일을 옮긴 뒤, 새 위치가 PATH에 들어 있는데도 예전 경로의 No such file or directory 오류가 날 수 있다. 같은 Bash가 이전 실행에서 찾은 파일 경로를 해시 테이블에 기억하고 있기 때문이다. 실패한 터미널에서 type과 hash -t로 그 기억을 확인하고, 해당 항목만 hash -d로 지우면 다음 실행에서 다시 찾게 할 수 있다.

이 설명은 hashdemo처럼 슬래시 없이 입력한 외부 명령에 해당한다. Bash는 이런 명령의 위치를 기억해 PATH 검색을 줄인다. 파일을 다른 디렉터리로 옮기는 것과 셸에 저장된 경로를 갱신하는 것은 별개다. GNU Bash의 명령 검색 설명 (새 탭에서 열림)에서 이 동작을 확인할 수 있다.

실패한 터미널에서 기억과 파일 배치를 비교한다

새 터미널을 열기 전에, 문제가 난 Bash에서 아래 명령을 실행한다. hashdemo는 실제로 실패한 명령 이름으로 바꾼다. 첫 명령은 같은 이름의 alias·함수·실행 파일을 살피고, 나머지는 현재 해석과 저장된 경로, PATH에서 찾을 수 있는 파일을 비교한다.

type -a hashdemo
type hashdemo
hash -t hashdemo
type -a -p hashdemo

별도 실험에서는 직접 만든 old-bin과 new-bin을 처음부터 PATH에 넣었다. old-bin/hashdemo를 한 번 실행해 경로를 기억시킨 뒤, 파일을 new-bin/hashdemo로 옮겼다. 그 사이 PATH에는 대입하지 않았다. 위 네 명령의 실제 출력은 다음 순서였다. 긴 공통 절대경로만 <실습폴더>로 줄였다.

hashdemo is <실습폴더>/new-bin/hashdemo
hashdemo is hashed (<실습폴더>/old-bin/hashdemo)
<실습폴더>/old-bin/hashdemo
<실습폴더>/new-bin/hashdemo

디스크에서 찾을 수 있는 파일과 셸이 기억한 파일이 달랐다. 이 상태에서 hashdemo를 실행하면 사라진 old-bin/hashdemo를 열려다 No such file or directory로 실패했고, 종료 코드는 127이었다. 반면 new-bin/hashdemo의 절대경로로 실행하면 성공했다. 이 비교로 새 파일 자체의 실행 실패와 저장된 옛 경로의 문제를 나눌 수 있었다.

여기서 type -P만으로 새 검색 결과를 확인하려 하면 헷갈릴 수 있다. 이 실험에서도 type -P hashdemo는 저장된 옛 경로를 출력했다. type 문서 (새 탭에서 열림)는 -p·-P가 저장된 값을 쓸 수 있으며, -a와 -p를 함께 주면 해시 테이블을 보지 않고 PATH를 검색한다고 설명한다.

첫 조회에 alias나 함수 정의가 보이면 그 정의부터 확인한다. 별도 비교에서도 hash -d hashdemo 뒤 alias와 함수는 각각 계속 실행됐다. 또 hash -t의 not found는 현재 테이블에 기억된 항목이 없다는 뜻이다. 그것만으로 프로그램이 설치되지 않았다고 판단하지 않는다.

사라진 경로의 항목만 지우고 다시 실행한다

캐시에 나온 파일이 실제로 없어졌고 PATH 검색은 원하는 새 파일을 찾는다면, 같은 Bash에서 다음처럼 해당 항목을 지운다. 재실행에는 확인하려는 명령에 필요한 인자를 붙인다.

hash -d hashdemo
hashdemo
hash -t hashdemo

실험에서 hash -d는 출력 없이 성공했다. 이어 실행한 파일이 자신의 경로를 출력했고, 마지막 조회에도 새 위치가 저장돼 있었다.

exec=<실습폴더>/new-bin/hashdemo
<실습폴더>/new-bin/hashdemo

다른 명령 staydemo의 기억은 그대로 남았다. 반면 같은 조건에서 hash -r을 쓰자 두 명령의 기억이 모두 사라졌다. 하나만 옮겼다면 hash -d 명령이름, 여러 명령의 배치를 바꾸어 전체 위치를 다시 찾게 할 때는 hash -r을 고를 수 있다. hash 문서 (새 탭에서 열림)에 각 삭제 범위가 명시돼 있다.

지운 뒤 PATH 검색에도 새 파일이 나오지 않으면, 현재 PATH에 들어 있는 디렉터리와 그 안 파일의 실행 권한을 확인한다. 캐시에 나온 파일이 여전히 존재한다면 같은 오류 문구라도 이 실험의 파일 이동 조건과 다르다. 그 파일의 실행 권한과 스크립트가 지정한 인터프리터 경로를 확인할 차례다.

PATH를 확인한 것과 다시 대입한 것은 다르다

printf '%s\n' "$PATH"로 읽는 것은 PATH 대입이 아니다. 반면 PATH="$PATH"처럼 같은 문자열을 다시 대입해도 해시 테이블이 비워진다. 실제 비교에서도 문자열은 같았지만 hashdemo와 staydemo의 기억이 모두 없어졌고, 다음 실행은 새 파일을 찾았다. 이는 위 hash 문서의 PATH 대입 규칙과 일치한다.

따라서 “파일을 옮긴 뒤에도 실패했다”는 관찰과 “PATH를 다시 설정하자 성공했다”는 관찰을 구분해야 한다. 후자는 검색 경로의 문자열 변화뿐 아니라 캐시 초기화 효과도 함께 확인해야 한다. 원인을 알아보려면 먼저 실패한 셸의 type·hash -t 결과를 남긴다.

사라진 파일을 실행 전에 다시 확인하게 할 수도 있다

파일 이동이 잦은 셸에서는 checkhash를 선택할 수 있다. 현재 상태를 조회한 뒤 켜려면 다음 두 명령을 같은 Bash에서 실행한다. 조회 결과의 -u는 꺼짐, -s는 켜짐이다.

shopt -p checkhash
shopt -s checkhash

별도 비교에서는 옛 경로가 저장되고 파일이 옮겨진 상태에서 이 옵션만 켰다. 실행 전 hash -t에는 여전히 옛 경로가 나왔지만, 다음 hashdemo 실행은 새 파일을 찾아 성공했고 저장된 경로도 바뀌었다. checkhash 문서 (새 탭에서 열림)는 기억한 파일이 사라졌을 때 일반 PATH 검색을 다시 수행한다고 설명한다. 옵션은 현재 셸에 적용되며, 실험에서는 시작 설정 파일을 수정하지 않았다.

이 옵션은 새 버전을 고르는 기능으로 해석하면 안 된다. 옛 파일과 새 파일을 모두 남긴 비교에서는 checkhash를 켜도 기억된 옛 파일이 실행됐다. 필요한 것이 사라진 경로의 복구인지, 남아 있는 여러 실행 파일 중 하나의 선택인지 먼저 나눈다.

실행 환경은 WSL2의 Ubuntu 24.04.4, Bash 5.2.21이었다. 새 Bash마다 경로 기억 기능을 켜고 POSIX 모드를 끈 뒤 비교했다. 읽은 GNU 매뉴얼은 Bash 유지보수자 사이트의 5.3판이며 실행 버전과 구분했다. 다른 셸, 사용자 시작 설정, 파일을 옮기는 도중의 동시 실행은 이번 실험에서 확인하지 않았다.

← 전체 글 보기