파일 경로는 하나의 인자로 전달합니다
file_path='./sample report.txt'
if [ -f "$file_path" ]; then
printf 'regular file: %s\n' "$file_path"
fi"$file_path"를 따옴표로 감싸면 공백이 있어도 인자 하나로 전달됩니다. [와 ]는 쉘이 구분할 수 있도록 주변에 공백이 필요합니다. -f는 일반 파일인지, -d는 디렉터리인지 확인합니다.
-e는 대상의 존재를 확인합니다. 대상이 사라진 심벌릭 링크는 -e가 거짓이어도 -L이 참일 수 있습니다. 존재를 먼저 검사해도 실제 사용 전에 파일이 바뀔 수 있으므로, 뒤의 파일 작업에서 발생하는 오류도 처리해야 합니다.
ls 출력은 파일 이름 목록을 안전하게 전달하는 형식이 아닙니다
rm $(ls …)처럼 쓰면 명령 출력이 공백이나 개행으로 나뉘고, 다시 파일 이름 확장을 겪을 수 있습니다. 화면에 보이는 한 줄을 곧 파일 한 개라고 가정하는 것이 문제입니다.
- 텍스트 목록을 다시 분리공백·개행이 이름에 포함되면 경계를 잃을 수 있습니다.
- find가 인자를 직접 전달-exec … {} +는 찾은 경로를 각각 별도 인자로 넘깁니다.
두 상자는 방법의 비교입니다. 인자 경계는 명령이 파일 이름 한 개를 어디까지로 읽는지를 뜻합니다.
find ./input -type f -exec printf '<%s>\n' {} +이 예제의 printf는 각 파일 이름을 인자 하나씩 받습니다. 표시 결과에 개행이 있더라도 인자 자체가 둘로 쪼개진 것은 아닙니다. 다른 프로그램으로 목록을 전달할 때는 -print0와 xargs -0처럼 양쪽이 NUL 구분을 이해하도록 맞출 수 있습니다.
파일 수를 세기 위해 파일 이름을 출력할 필요는 없습니다
set -o pipefail
find ./input -type f -printf 'x' | wc -cGNU find가 일반 파일 하나를 찾을 때마다 ASCII 문자 x 하나를 출력합니다. wc는 그 바이트 수를 세므로 파일 이름에 포함된 공백이나 개행의 영향을 받지 않습니다. 숨김 파일도 탐색하고, 하위 디렉터리도 포함합니다.
이 값은 디렉터리에서 발견한 일반 파일 경로 수입니다. 하드 링크가 있으면 여러 경로가 같은 inode를 가리킬 수 있으므로 서로 다른 inode 개수와 같다고 할 수 없습니다. 권한 오류나 탐색 도중 변경이 있으면 완전한 스냅샷도 아닙니다. pipefail을 켜면 탐색 실패가 파이프라인 상태에서 가려지는 것을 줄일 수 있습니다.
처리할 조건과 범위를 먼저 좁힙니다
find ./input -depth -maxdepth 1 -type f ! -name 'keep.txt' -print현재 input 디렉터리 바로 아래의 일반 파일 중 keep.txt를 제외한 항목을 출력합니다. -maxdepth 1은 재귀 범위를 제한하고, -type f는 디렉터리와 심벌릭 링크 자체를 제외합니다. !는 다음 조건의 결과를 반대로 바꿉니다.
이 명령은 목록만 출력합니다. 실제로 삭제하려면 대상 목록을 확인한 뒤 같은 조건의 마지막 -print를 -delete로 바꿉니다. GNU find의 -delete는 -depth를 자동으로 켜므로, 미리 확인하는 명령에도 -depth를 넣어 순서를 맞췄습니다. -delete와 -prune을 섞으면 기대한 제외 조건이 동작하지 않을 수 있습니다.
출력한 뒤 파일시스템이 바뀌면 실제 처리 대상도 달라질 수 있습니다. 여러 사용자가 동시에 수정하는 디렉터리를 검사와 실행 두 단계만으로 고정된 대상으로 취급하면 안 됩니다.