찾기: 정규식을 사용하여 경로에 특정 디렉터리 이름이 있지만 경로에 다른 특정 디렉터리 이름이 없는 모든 파일을 가져옵니다.

찾기: 정규식을 사용하여 경로에 특정 디렉터리 이름이 있지만 경로에 다른 특정 디렉터리 이름이 없는 모든 파일을 가져옵니다.

find를 사용하여 경로에 특정 디렉터리가 있지만 파일 경로에 다른 특정 디렉터리가 없는 모든 파일 이름을 반환하려고 합니다. 그것은 다음과 같습니다:

myRegex= <regex> 
targetDir= <source directory>
find $targetDir -regex $myRegex -print

하나의 find 명령을 다른 명령에 파이프하여 이 작업을 수행할 수도 있다는 것을 알고 있지만 단일 정규식을 사용하여 이 작업을 수행하는 방법을 알고 싶습니다.

예를 들어, 모든 파일의 경로에 "good" 디렉터리가 있지만 조합에 관계없이 경로의 어느 곳에도 "bad" 디렉터리가 없기를 원합니다. 몇 가지 예:

/good/file_I_want.txt #Captured
/good/bad/file_I_dont_want.txt #Not captured

/dir1/good/file_I_want.txt #Captured
/dir2/good/bad/file_I_dont_want.txt #Not captured

/dir1/good/dir2/file_I_want.txt #Captured
/dir1/good/dir2/bad/file_I_want.txt #Not captured

/bad/dir1/good/file_I_dont_want.txt #Not captured

일부 파일 이름에는 "좋은" 또는 "나쁜"이 포함될 수 있지만 디렉터리 이름만 고려하고 싶습니다.

/good/bad.txt #Captured
/bad/good.txt #Not captured

내 연구에 따르면 부정적인 예측과 부정적인 예측을 사용해야 하는 것으로 나타났습니다. 그러나 지금까지 시도한 것은 아무것도 작동하지 않았습니다. 도움을 주시면 대단히 감사하겠습니다. 감사해요.

답변1

Inian이 말했듯이, 그럴 필요는 없습니다 -regex(비표준이며 구문은 지원되는 구현에 따라 크게 다릅니다 -regex).

이것을 사용할 수도 있지만 이름이 지정된 디렉토리로 이동하지 않도록 -path지시할 수도 있습니다. 이는 나중에 해당 파일을 필터링할 수 있도록 그 안의 모든 파일을 검색하는 것보다 더 효율적입니다 .findbad-path

LC_ALL=C find . -name bad -prune -o -path '*/good/*.txt' -type f -print

( LC_ALL=C따라서 와일드카드는 바이트 시퀀스 find*​​로케일에서 유효한 문자를 형성하지 않는 파일 이름을 차단하지 않습니다.)

또는 여러 폴더 이름의 경우:

LC_ALL=C find . '(' -name bad -o -name worse ')' -prune -o \
  '(' -path '*/good/*' -o -path '*/better/*' ')' -name '*.txt' -type f -print

를 사용하면 zsh다음 작업도 수행할 수 있습니다.

set -o extendedglob # best in ~/.zshrc
print -rC1 -- (^bad/)#*.txt~^*/good/*(ND.)
print -rC1 -- (^(bad|worse)/)#*.txt~^*/(good|better)/*(ND.)

또는 배열 목록의 경우:

good=(good better best)
bad=(bad worse worst)
print -rC1 -- (^(${(~j[|])bad})/)#*.txt~^*/(${(~j[|])good})/*(ND.)

도착하다아니요bad또는 (와 같이 덜 효율적)이라는 이름의 디렉토리를 입력하십시오 -path '*/good/*' ! -path '*/bad/*'.

print -rC1 -- **/*.txt~*/bad/*~^*/good/*(ND.)

중간 zsh -o extendedglob, ~와는 별개로(NAND) 와일드카드 연산자 while ^은 부정 연산자이며 #regexp와 같이 0개 이상의 선행 콘텐츠입니다 *. ${(~j[|])array}배열의 요소를 연결 |하고 |이를 리터럴이 아닌 전역 연산자로 처리하는 데 |사용 됩니다 ~.

에서는 zsh일치 후 PCRE를 사용할 수 있습니다 set -o rematchpcre.

set -o rematchpcre
regex='^(?!.*/bad/).*/good/.*\.txt\Z'
print -rC1 -- **/*(ND.e['[[ $REPLY =~ $regex ]]'])

그러나 모든 파일(디렉토리의 파일 포함)에 대한 셸 코드를 평가하는 것은 bad다른 솔루션보다 훨씬 느릴 수 있습니다.

또한 PCRE(zsh glob과 반대)는 로케일에서 유효한 문자를 형성하지 않는 바이트 시퀀스를 차단하고 UTF-8 이외의 멀티바이트 문자 세트를 지원하지 않는다는 점에 유의하세요. 로케일을 C위와 같이 수정하면 find이 특정 모드의 문제가 해결됩니다.

[[ =~ ]]에서와 같이 확장된 정규식 일치를 수행하려는 경우 PCRE 일치를 수행하는 대신 PCRE 모듈( ) bash을 로드하고 사용할 수도 있습니다 .zmodload zsh/pcre[[ -pcre-match ]][[ =~ ]]

또는 다음 명령을 사용하여 필터링할 수 있습니다 grep -zP(GNU grep또는 호환 가능하다고 가정).

regex='^(?!.*/bad/).*/good/.*\.txt\Z'
find . -type f -print0 |
  LC_ALL=C grep -zPe "$regex" |
  tr '\0' '\n'

( find모든 디렉토리 bad의 모든 파일이 여전히 발견되지만).

이러한 파일에 대해 작업을 수행해야 하는 경우(한 줄에 하나씩 인쇄하는 것 제외) tr '\0' '\n'로 바꾸십시오.xargs -r0 cmd


find어쨌든, 나는 둘러보기 연산자로 필요한 Perl 유사 또는 Vim 유사 정규 표현식을 지원하는 구현을 모릅니다 .

답변2

이를 위해 정규식을 사용할 필요는 없습니다. 조건자를 사용하여 -path모든 수준에서 특정 이름을 가진 디렉터리를 제외 할 수 있습니다.

find . -type f -path '*/good/*' '!' -path '*/bad/*'

답변3

아마도 강력한 필터링보다 효율성이 낮고(확실하지는 않지만) "정확함"이 덜하지만 find(예를 들어 grep여기서 순진한 내용은 개행 문자가 포함된 이름에 적용되지 않습니다. 이러한 경우는 매우 드물고 일반적으로 오류를 나타냄) 일반적으로 더 쉽습니다. grep더 간단한 일치 및 역방향 일치를 사용하여 결과를 지속적으로 필터링하기 위해 일부 인스턴스를 스택합니다.-v

실제로 디렉토리 이름을 찾으려면 하위 문자열에 좀 더 주의가 필요하지만 일반적으로 이해하기 쉽고 필요한 모든 작업을 수행하는 구문을 제공합니다!

find ./ | grep "/good/" | grep -v "/bad/" | grep '\.txt$'

관련 정보