Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

find가 “paths must precede expression”이라고 하나요? 명령을 바꾸기 전에 셸 확장을 증명하세요

이 오류는 대개 find가 해석하기 전에 셸이나 래퍼가 인수 목록을 바꿨다는 뜻이며 시작 경로가 틀렸다는 증거는 아닙니다. 실제 argv를 캡처하고 시작점과 식을 분리한 뒤 find용 패턴을 인용하고, 0개·1개·여러 개 일치에서 시험한 후 파괴적 동작을 복원하세요.

인용되지 않은 셸 와일드카드가 find 해석 전에 여러 인수로 확장되는 개념도
개념도: 입력한 명령문이 아니라 find가 실제로 받은 인수 벡터를 확인합니다. Watch at Ease

이 메시지는 find가 받은 시작점과 평가식 사이의 경계를 유지하지 못했다는 뜻입니다. 그 자체로 -name 앞의 디렉터리가 틀렸다는 증거는 아닙니다.

가장 가치 있는 증거는 실제 인수 벡터입니다. 셸이나 래퍼가 find에 전달한 값을 증명하고 각 토큰의 역할을 분류한 뒤, 0개·1개·여러 개 일치에서 수정안을 검증하고 파일 변경 동작을 복원하세요.

1. 원래 명령과 실제 argv 경계를 보존하기

셸, 작업 디렉터리, find 버전, 정확한 명령, 종료 상태와 stderr를 기록합니다. 안전한 재현에서는 각 인수를 따로 인용해 출력하고 비밀을 로그에 남기거나 eval로 명령을 재구성하지 마세요.

대화형 셸, 스크립트, 별칭, 변수, 빌드 도구를 거치면 화면상 같은 명령도 다른 argv가 될 수 있어 표시 문자열만으로는 부족합니다.

2. 일치 0개·1개·여러 개를 재현하기

무해한 시험 디렉터리에서 같은 패턴을 실행합니다. 인용되지 않은 *.txt는 한 단어로 남거나, 경로 하나로 확장돼 우연히 동작하거나, 여러 경로로 확장돼 추가 시작점으로 해석될 수 있습니다.

find가 직접 일치시킬 패턴은 인용하거나 이스케이프합니다. Bash와 zsh 등의 불일치 동작 차이는 증거로 기록하고 추측으로 고치지 않습니다.

3. 모든 토큰의 역할 분류하기

전달된 인수를 한 줄씩 적고 실제 시작 경로, -name 같은 테스트, -print 같은 동작으로 표시한 다음 각 primary가 요구하는 인수 수를 확인합니다.

모르는 토큰을 모두 앞으로 옮기지 말고 경로, 옵션, 테스트 피연산자, 그룹 기호, 동작 중 무엇인지 설치된 find 문서로 확인합니다.

4. 변수와 래퍼에서 경계를 보존하기

Bash의 인용되지 않은 매개변수 확장은 단어 분할과 경로명 확장을 거칩니다. 여러 인수는 배열을 사용하고 한 인수여야 하는 값은 인용하며 별칭, 함수, 서비스 래퍼와 빌드 치환을 따로 검사합니다.

eval이나 하나로 이어 붙인 문자열로 고치지 마세요. 재해석은 공백과 와일드카드 의미를 바꾸고 주입 경로를 만들 수 있습니다.

5. 파괴적 동작 전에 수정 증명하기

먼저 변경 동작을 -print로 바꾸고 0개·1개·여러 개 일치와 공백 또는 선행 하이픈이 있는 이름을 검증하며 실제 스케줄러에서도 같은 argv가 도착하는지 확인합니다.

선택 집합이 정확할 때만 작은 시험 범위와 복구 계획 아래 -delete나 -exec를 복원합니다. 진단이 사라지고 출력이 정확하며 토큰 역할이 바뀌지 않아야 승인합니다.

셸 확장, 시작 경로, find 식과 래퍼 경계를 나누는 결정도
개념도: 각 토큰을 역할별로 분류한 뒤 출력 전용 사례로 수정안을 검증합니다. Watch at Ease