Devin.KR

경로를 따라 파일 찾기

65분 안팎

학습 목표

절대·상대 경로를 구분하고 파일을 검색합니다.

개념

왜 경로 오류를 먼저 분리하는가

제목 파일이 분명히 보이는데 cat이 읽지 못하는 상황은 신입이 자주 만나는 문제입니다. 파일이 없는 경우와 다른 위치에서 찾는 경우는 수정 방법이 다릅니다. 이번 레슨은 파일을 복제해서 오류를 감추기보다 찾는 기준을 확인하도록 훈련합니다. 독서 기록 프로젝트 루트에는 data/sample.txt가 있습니다. 루트에서 성공한 명령도 data 폴더로 이동하면 실패할 수 있습니다. 파일 내용이 바뀌지 않았는데 실행 결과가 달라지는 이유를 현재 작업 디렉터리로 설명합니다.

절대 경로와 상대 경로

macOS·Linux에서 /로 시작하는 경로는 파일 시스템 루트부터 지정하는 절대 경로입니다. 사용자 이름과 설치 위치에 따라 실제 절대 경로가 달라지므로 강사의 경로를 그대로 붙여 넣지 않습니다. 상대 경로는 현재 작업 디렉터리를 출발점으로 해석합니다. data/sample.txt는 현재 위치 아래의 data 폴더 안 파일을 뜻합니다. ./data/sample.txt에서 점은 현재 디렉터리입니다. ../data/sample.txt에서 점 두 개는 부모 디렉터리입니다. 경로의 /는 폴더 경계를 구분합니다. 이 레슨은 심볼릭 링크가 없는 내려받은 실습 폴더를 기준으로 설명합니다.

이동을 그림 대신 명령으로 검증하기

루트에서 cd data를 하면 작업 디렉터리가 한 단계 내려갑니다. 이때 cat data/sample.txt는 data 안의 또 다른 data를 찾게 됩니다. cat sample.txt로 읽거나 cat ../data/sample.txt로 부모를 거쳐 같은 파일에 도달할 수 있습니다. cd ..로 돌아온 뒤에는 원래 명령이 다시 맞습니다. cd를 여러 번 한 후 위치가 헷갈리면 추측으로 ../를 추가하지 말고 pwd를 실행합니다. 현재 위치를 먼저 적고 대상까지의 경로를 계산하면 변경할 것은 경로인지 작업 위치인지 결정할 수 있습니다.

찾기는 범위를 정해서 시작한다

find . -type f -name "sample.txt"는 현재 위치 아래에서 일반 파일 중 이름이 일치하는 항목을 찾습니다. -type f는 폴더를 결과에서 제외합니다. -name은 전체 경로가 아니라 마지막 이름에 적용됩니다. *.txt 같은 패턴에는 따옴표를 붙여 셸이 먼저 펼치지 않게 합니다. 찾지 못해도 출력이 빈 상태로 끝날 수 있으므로 빈 결과를 내용이 빈 파일과 혼동하지 않습니다. 프로젝트 밖까지 넓히기 전에 시작 경로가 맞는지 확인합니다. 이 실습에서는 읽기만 수행하고 삭제 옵션은 사용하지 않습니다.

찾은 뒤에는 내용을 확인한다

이름이 같은 sample.txt가 두 폴더에 있으면 검색 성공만으로 올바른 자료라고 할 수 없습니다. find 결과의 전체 경로를 읽고 cat으로 제목을 확인합니다. 경로에 공백이 있으면 cat "찾은 경로"처럼 묶습니다. 다른 사람에게 재현 절차를 줄 때는 대상 이름뿐 아니라 실행 시작 폴더도 함께 씁니다. 루트에서 실행한다는 설명과 data에서 실행한다는 설명은 서로 다른 상대 경로를 요구합니다. 기록에는 명령 입력 전의 위치, 입력한 명령, 성공 또는 실패 결과를 남깁니다. 개인 사용자 이름이 포함된 절대 경로는 공유 전에 가릴 수 있습니다.

스크립트 위치를 기준으로 읽기

레슨의 read-title.sh는 어느 작업 디렉터리에서 실행해도 자신의 data/sample.txt를 읽어야 합니다. Bash에서 $0는 실행한 스크립트 이름을 담고 dirname은 그 이름의 폴더 부분을 얻습니다. 스크립트에서는 그 폴더로 이동해 pwd로 절대 기준 경로를 얻고 base_dir에 담습니다. 괄호 안 명령 치환은 별도 환경에서 실행되므로 호출한 셸의 위치를 바꾸지 않습니다. CDPATH를 비워 cd가 다른 검색 기준이나 부가 출력을 사용하지 않도록 합니다. 이 패턴은 직접 실행하는 일반 파일 스크립트에 사용합니다. source 방식이나 심볼릭 링크 해석은 이번 범위에 포함하지 않습니다.

따옴표가 경로 계약을 지킨다

base_dir를 구한 후 cat "$base_dir/data/sample.txt"로 읽습니다. 변수 확장 결과를 큰따옴표로 묶지 않으면 공백을 포함한 경로가 여러 인자로 나뉠 수 있습니다. 셸 문법 전체를 지금 암기할 필요는 없습니다. 제공한 기준 경로 구하는 줄을 유지하고 실제 파일을 읽는 마지막 줄의 대상만 정확하게 연결합니다. starter의 cat data/sample.txt는 프로젝트 루트에서 성공합니다. 그러나 data와 외부 폴더에서 실패합니다. 한 번 성공한 실행을 모든 위치에서의 성공으로 일반화하지 않는 것이 이번 검사 목적입니다.

오류에 따라 다음 행동을 정한다

cat: data/sample.txt: No such file or directory처럼 대상이 표시되면 pwd, find, cat 순서로 확인합니다. 파일이 보이면 작업 기준을 고치고, 파일이 정말 없으면 starter가 제대로 풀렸는지 확인합니다. Permission denied라면 존재 문제와 접근 문제를 나누며 개인 실습 폴더인지 확인합니다. 자료를 찾지 못했다고 빈 파일을 새로 만드는 행동은 원래 제목이 사라진 것처럼 보이게 합니다. 상대 경로 실패를 수정할 때 입력 파일 자체는 유지합니다. 검사기는 같은 샘플의 내용이 변하지 않았는지도 확인합니다.

미션 문서에 남길 실행 근거

미션 docs/runtime.md에는 작업 디렉터리와 절대·상대 경로의 차이를 실제 실패 사례로 적습니다. data에서 cat data/sample.txt가 실패했고 ../data/sample.txt로 읽었다는 설명이면 기준 변화가 드러납니다. 명령만 나열하면 왜 고쳤는지를 알기 어려우므로 원래 요청이 data/data/sample.txt를 가리켰다는 이유도 덧붙입니다. 이번 레슨이 끝나면 pwd로 위치를 말하고 find로 자료를 찾으며 cat으로 내용을 확인할 수 있어야 합니다. 레슨 검사에는 루트·data·외부 폴더가 포함됩니다. 외부 폴더에서 실행하는 경우에도 같은 제목을 읽는다는 사실이 기준 경로를 제대로 선택했다는 증거입니다.

따라하기

검색용 공간 준비

새 reading-path 폴더에서 시작합니다. 네 단계를 같은 터미널에서 실행합니다.

mkdir -p reading-path/data
cd reading-path
printf "달빛 도서관\n" > data/sample.txt
find . -type f -name "sample.txt"

실행 결과

./data/sample.txt

현재 위치 변화

마지막 명령은 의도적으로 실패합니다. pwd의 실제 경로는 각자 다릅니다. 오류 대상이 data/data/sample.txt가 되는 이유를 적습니다. 출력은 환경별 경로와 오류 문구가 달라 생략합니다.

cd data
pwd
cat data/sample.txt

부모 기준으로 수정

작업 위치는 data인 상태를 유지합니다.

cat ../data/sample.txt

실행 결과

달빛 도서관

검색 범위와 절대 경로

패턴은 따옴표로 묶습니다. 자신의 절대 경로로 같은 자료를 읽습니다.

cd ..
find . -type f -name "*.txt"
sample_path="$(pwd)/data/sample.txt"
cat "$sample_path"

실행 결과

./data/sample.txt
달빛 도서관

확인 문제

실습

read-title.sh를 스크립트 위치 기준으로 수정합니다. 루트·data·외부 작업 위치에서 같은 원본 제목을 읽고 원본은 변경하지 않습니다. starter의 README.md에서 실행 방법과 검사 대상을 확인합니다. tests/check.py와 check.sh는 변경하지 않습니다. 일부 검사가 실패하는 시작 상태를 확인한 뒤 수정하고 다시 검사합니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

모든 검사 줄이 PASS이며 마지막 줄은 ALL PASS, 종료 코드는 0입니다.

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • 파일 경로 때문에 실행이 실패했을 때 확인 순서를 설명합니다.