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

빌드노트

find에서 제외한 폴더 이름이 출력되는 이유: -prune과 -print

GNU find의 -prune은 하강을 멈추고 참을 반환한다. 작은 임시 트리에서 기본 출력과 명시적 -print의 위치를 비교하고, 괄호·-o·시작 경로·-depth로 결과가 달라지는 이유를 확인한다.

GNU find에서 -prune으로 폴더를 제외해도 그 폴더 이름은 출력될 수 있다. -prune은 디렉터리 안으로 내려가지 않게 하고 참을 반환한다. 하위 탐색 중단과 현재 경로의 출력은 별개다. 제외 폴더를 숨기고 원하는 파일만 출력하려면 -o 오른쪽에 파일 조건과 명시적인 -print를 함께 둔다.

현재 위치의 tree에서 tree/skip을 건너뛰고 일반 txt 파일만 출력하는 명령이다. 자기 폴더에 적용할 때는 시작점 tree와 제외 경로 tree/skip을 함께 바꾼다. 아래 입력은 Bash와 GNU find를 기준으로 한다.

find tree -path 'tree/skip' -prune -o \( -type f -name '*.txt' -print \)

tree/skip에서는 왼쪽의 경로 조건과 -prune이 참이므로 -o 오른쪽을 평가하지 않는다. 따라서 그 디렉터리는 출력하지 않고 안으로도 내려가지 않는다. 다른 경로는 오른쪽에서 일반 파일인지, 이름이 txt로 끝나는지 검사한 뒤 출력한다. GNU 디렉터리 탐색 문서 (새 탭에서 열림)도 제외 폴더의 이름을 숨기는 이유를 이 분기로 설명한다.

오른쪽 괄호는 출력할 분기를 드러낸 것이다. 나란히 쓴 조건 사이에는 AND인 -a가 생략되어 있고, AND는 OR인 -o보다 먼저 묶이므로 이 괄호를 생략해도 같은 결과다. AND의 왼쪽이 거짓이면 오른쪽을, OR의 왼쪽이 참이면 오른쪽을 건너뛰는 것이 단락 평가다. GNU 연산자 문서 (새 탭에서 열림)

Bash가 괄호를 해석하지 않도록 \(와 \)로 이스케이프한다. '*.txt'도 셸이 먼저 펼치지 않게 인용한 패턴이다.

같은 트리에서 출력 위치만 바꿨다

새 임시 디렉터리에 빈 파일 네 개를 만들어 비교했다. 직접 재현하려면 Bash에서 다음 준비 입력을 실행한 뒤, 같은 셸에서 첫 명령을 실행한다. mktemp, mkdir, touch가 필요하며 준비 중 오류가 나면 뒤의 비교를 진행하지 않는다.

lab=$(mktemp -d) &&
cd "$lab" &&
mkdir -p tree/docs tree/skip/deeper &&
touch tree/root.txt tree/docs/keep.txt tree/skip/hidden.txt \
  tree/skip/deeper/nested.txt

첫 명령은 tree/docs/keep.txt와 tree/root.txt 두 줄을 출력했다. 제외 폴더와 그 안의 두 파일은 없었다. 비교할 것은 경로의 포함 여부이며 출력 순서는 달라질 수 있다.

여기서 -print만 빼자 두 txt 경로에 tree/skip 한 줄이 더해졌다. 하위 파일은 여전히 나오지 않았다. GNU find 식 문서 (새 탭에서 열림)에 따르면 이처럼 검사와 -prune만 있는 식은 전체 식이 참인 경로를 기본 출력한다. 제외 폴더도 -prune에서 참이므로 출력 대상이다. 오른쪽 분기까지 없애고 -path 'tree/skip' -prune만 남긴 비교에서는 tree/skip만 출력됐다.

반면 명시적 -print를 넣으면 기본 출력은 추가되지 않는다. 해당 경로에서 그 위치까지 평가가 도달해야 출력된다. 명령줄 끝에 썼다는 이유만으로 모든 경로에 실행되는 것은 아니다.

괄호 밖으로 -print를 옮기면 폴더가 다시 나온다

첫 명령과 달리 OR 두 갈래 전체를 묶고 그 밖에 -print를 놓아 보면 차이가 드러난다. 같은 실습 디렉터리에서 다음을 실행한다.

find tree \( -path 'tree/skip' -prune -o -type f -name '*.txt' \) -print

이 식은 앞의 txt 두 개와 tree/skip을 출력했다. 제외 폴더에서도 괄호 전체가 참이라 괄호 밖의 -print가 실행되기 때문이다. 폴더를 숨기려면 첫 명령처럼 출력 동작을 오른쪽 분기 안에 둔다.

-o를 아예 빼는 수정도 답이 아니다. 첫 명령에서 -o만 제거한 비교는 종료 코드 0인데 출력은 비어 있었다. 일반 파일은 왼쪽 제외 경로 조건을 통과하지 못하고, 제외 디렉터리는 오른쪽 -type f를 통과하지 못한다. 출력이 없을 때는 오류 여부와 함께 두 갈래를 실수로 AND로 연결했는지 확인한다.

폴더 안의 파일까지 나오면 경로와 -depth를 본다

폴더 이름 한 줄이 남는 경우와 하위 파일이 나오는 경우는 원인이 다를 수 있다. GNU 경로 패턴 문서 (새 탭에서 열림)에 따르면 -path는 명령줄의 시작점을 포함한 경로와 비교한다. 첫 명령의 시작점만 ./tree로 바꾸고 패턴을 'tree/skip'으로 두자 제외 폴더 안의 txt 두 개도 출력됐다. 패턴을 './tree/skip'으로 맞추자 다시 바깥 txt 두 개만 나왔다.

기존 명령에 -depth가 있는지도 확인한다. 이 옵션은 디렉터리보다 하위 항목을 먼저 방문하므로, 나중에 디렉터리에서 실행되는 -prune으로 이미 방문한 내용을 막을 수 없다. 첫 명령에 -depth를 추가한 비교에서도 hidden.txt와 nested.txt가 출력됐다. 이 제한은 앞의 GNU 디렉터리 탐색 문서에도 명시되어 있다.

실행 환경은 WSL2 Ubuntu 24.04.4의 GNU findutils 4.9.0, Bash 5.2.21이었다. 자기 구현과 버전은 find --version으로 확인할 수 있다. 읽은 온라인 매뉴얼의 표기 버전은 4.10.0.77-733bb다. 이 결과는 작은 합성 트리의 경로 선택을 확인한 것으로, 다른 find 구현, 권한 오류, 탐색 중 파일 변경, 심볼릭 링크를 따라가는 조건은 실행하지 않았다.

← 전체 글 보기