찾기 명령: 특정 폴더의 파일 패턴 제외

찾기 명령: 특정 폴더의 파일 패턴 제외

find폴더 내의 특정 파일 패턴을 제외하고 해당 폴더의 하위 폴더는 제외하는 명령을 원합니다 . 예를 들어 제외하려는 경우 subdir1/subdir1.1/UndesiredFiles*.tgz별표는 폴더 이름 구분 기호를 포함한 연속 문자와 일치하므로 다음은 작동하지 않습니다 /.

find * -not -path 'subdir1/subdir1.1/UndesiredFiles*.tgz'

위에서는 제외하고 싶지 않은 다음 항목을 제외합니다.

subdir1/subdir1.1/UndesiredFilesAndMore/*.tgz
subdir1/subdir1.1/UndesiredFilesAndMore/StillMore/*.tgz

저는 Gnu find버전 4.9.0을 사용하고 있습니다.

답변1

일부 find구현은 쉘 glob 패턴 대신 정규식(구현 및 옵션 또는 기타 조건자에 따라 변형이 다르지만)을 사용한다는 점을 제외하고 -regex동일한 조건자를 지원합니다. 비표준 BSD 스타일 조건자를 지원한다는 -path점을 고려하면 아마도 그 중 하나일 것입니다.find-not

LC_ALL=C find . ! -regex '\./subdir1/subdir1\.1/UndesiredFiles[^/]*\.tgz'

*glob 연산자(regexp와 동일 .*: 0개 이상의 문자)를 regexp [^/*](0개 이상의 문자 제외 /) 로 대체 합니다 .

정규식은 기본적으로 고정되어 있으므로 명시적인 ^또는 가 필요하지 않습니다 $.

모든 문자와 일치하는 정규식 연산자와 마찬가지로 리터럴만 일치하도록 이스케이프를 .사용해야 합니다 \.( [.]가능하더라도). s는 파일 이름에서 매우 일반적 .이므로 간과하기 쉽습니다 ..

LC_ALL=C모든 파일 및 디렉터리 이름이 사용자 로케일의 유효한 문자로만 구성되도록 보장할 수 없는 경우 일반적으로 필수입니다 (이는 -pathbtw에도 적용됩니다).

BSD에서는 표준 기본 정규식을 사용하며 -regexfor 또는 와 같은 옵션을 사용하여 표준 확장 정규식으로 변경할 수 있습니다. GNU의 경우 기본적으로 이는 emacs 정규식의 고대 버전이지만 다양한 다른 버전으로 변경될 수 있습니다.-Egrepsedfind-regextype술부. 그럼에도 불구하고 위의 특정 정규식은 어떤 변형에서도 작동합니다.


find지원되지 않는 의 경우 다음 -regex을 수행할 수 있습니다.

LC_ALL=C find . ! '(' -path './subdir1/subdir1.1/UndesiredFiles*.tgz' \
  ! -path './subdir1/subdir1.1/*/*' ')'

즉, 하나 이상의 가 포함된 일치 항목을 ./subdir1/subdir1.1/UndesiredFiles*.tgz제외하고 필터링합니다 .*/

또는 다음 perl을 필터링할 수 있습니다.

find . -exec printf '%s\0' {} + |
  perl -l -0ne 'print unless m{^\Q./subdir1/subdir1.1/UndesiredFiles\E[^/]*\.tgz\z}'

여기서는 \Q...\E내용을 고정 문자열로 처리하여 정규식 연산자를 이스케이프할 필요가 없습니다. 여기에서는 정규식을 ^시작과 끝 부분에 고정 해야 합니다 ( 정규식은 끝이나 후행 줄 바꿈이 Perl에서 일치하지 않으므로 파일이 "잘못" 제외됩니다 ).\z$$'UndesiredFiles.tgz\n'

(경로를 인수로 사용하여 명령을 실행하여 대체 printsystem "cmd", $_)

일부(대부분) find구현은 -exec printf '%s\0' {} +로 대체될 수 있습니다 -print0. 일부 xargs구현은 -0또는 옵션을 통해 -d '\0'이 출력 형식을 지원합니다 .

find . -print0 |
  perl -0 -lne 'print unless m{^\Q./subdir1/subdir1\.1/UndesiredFiles\E[^/]*\.tgz\z}' |
  xargs -r0 cmd

-l옵션이 이동됨뒤쪽에 -0출력 레코드 구분 기호도 NUL입니다.


zsh쉘을 사용하는 경우에는 이것이 필요하지 않습니다 find. 다음을 수행할 수 있습니다.

set -o extendedglob
print -rC1 -- **/*~subdir1/subdir1.1/UndesiredFiles[^/]#.tgz(ND)

여기서 #정규식과 동등한 Extendedglob은 다음 *과 같습니다.~와는 별개로/설마and 연산자는 일치하는 전역 확장 동작에 (ND)적용됩니다 nullglob(일치하지 않으면 아무것도 확장되지 않음) 및 (숨겨진 파일 포함) . match 의 동작을 더 일치시키기 위해 목록 에 한정자를 추가 할 수도 있습니다 .dotglobfindoNNofind

print -rC1 -- printrs 열이지만 1 C물론 다른 명령을 사용하거나 목록을 반복할 수도 있습니다 for.

**/*(하위 디렉터리 수에 관계없이 모든 이름을 가진 모든 파일과 일치, 축약됨) 이 옵션이 설정되면 (*/)#*로 축약될 수 있습니다.**globstarshort


어쨌든, 이들 모두는 제외되지만 ./subdir1/subdir1.1/UndesiredFiles-whatever.tgz,아니요Exclude ./subdir1/subdir1.1/UndesiredFiles-whatever.tgz/other/file패턴을 조정하거나 -prune find조건자를 사용하여 제외해야 합니다.

관련 정보