find를 재귀적으로 호출하는 방법이 있나요?
다른 패턴과 일치하는 디렉터리에서만 특정 패턴과 일치하는 파일을 검색하고 싶습니다.
원래:
for each (sub)directory D matching "*.data"
do
for each file F in directory D (with subdirs) matching "*.important.txt"
do
run command foo on F
done
done
이제 가장 안쪽 요구 사항(F에서 foo 명령 실행) 이것은 매우 간단합니다.
find . -type d -name "*.data" \
-exec find \{\} -type f -name "*.important.txt" \;
그러나 내부에서 명령을 전달하는 방법을 찾지 못했습니다 find
. 예를 들어 다음을 인쇄해 보세요.찾기: '-exec' 인수 누락내부 조회가 호출될 때마다:
find . -type d -name "*.data" \
-exec find \{\} -type f -name "*.important.txt" \
-exec "foo \{\} \;" \;
모든 솔루션은 posix 규격(스크립트에서 실행 가능)이어야 합니다 /bin/sh
. 나는 해결책을 찾고 있는 것이 아니다
- 내부 조회를 별도의 쉘 스크립트로 래핑
- 내부 조회를 bash 기능으로 래핑
답변1
find
결과를 자체적으로 실행하려면 (or) -c
인수를 사용하여 외부 find 명령이 내부 결과를 특별하게 처리하지 못하도록 할 수 있습니다. 그러나 외부 조회 결과를 다음을 사용하여 확장할 수 있는 매개변수로 전달해야 합니다.sh
bash
{}
sh
$0
find . -type d -name "*.data" \
-exec sh -c 'find "$0" -type f -name "*.important.txt" -exec echo \{\} \;' \{\} \;
참고: 공백이 포함된 디렉터리 이름 문제를 방지하려면 $0
따옴표( "$0"
)를 사용해야 합니다.
find -exec
이는 털이 많은 탈출 없이 임의로 깊은 중첩을 허용하지 않기 때문에 실제로 "재귀적" 솔루션은 아니지만 예제에서 요청한 두 가지 수준을 지원합니다 .
귀하의 예가 실제 문제와 유사하다면 매개변수를 사용하여 다음 -path
을 찾아볼 수도 있습니다.
find . -path '*.data/*important.txt'
답변2
bash 버전(POSIX와 호환되지 않음)
#!/bin/bash
find . -type d -name 'a *' -print0 \
| while IFS= read -r -d '' dir ; do
find "$dir" -type f -name "*.c" -exec echo \{\} \;
done
질문:
(나쁜) sh 버전(POSIX 호환)
#!/bin/sh
# WARNING: while this will work on directory names with spaces,
# it will break on directory names that contain newlines
find . -type d -name 'a *' -print \
| while IFS= read -r dir ; do
find "$dir" -type f -name "*.c" -exec echo \{\} \;
done
문제: 주석에서 언급했듯이 개행 문자가 포함된 디렉토리 이름에서 중단됩니다. 이것이 실제 문제라고 생각하지 않을 수도 있지만 스크립트에 불필요한 취약점을 추가합니다. 어쩌면 다른 프로그램에 그러한 디렉토리 등을 생성하는 버그가 있을 수 있습니다.
(더 나은) sh 버전
바라보다이안 로버트슨의 답변
그런데. POSIX와 호환되는 스크립트가 필요한 경우 다음을 사용하십시오.shellcheck
. 예를 들어 read -d
POSIX에는 정의가 없다는 점을 알 수 있습니다 .