이름에 문자열이 포함 된 파일이 포함 된 하위 디렉토리 목록 가져 오기


45

이름이 특정 패턴과 일치하는 파일을 포함하는 서브 디렉토리 목록을 얻으려면 어떻게해야합니까?

더 구체적으로 말하면, 파일 이름에 'f'라는 문자가있는 파일이 들어있는 디렉토리를 찾고 있습니다.

이상적으로는 목록에 중복이없고 파일 이름이없는 경로 만 포함됩니다.

답변:


43
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq

위의 내용은 현재 디렉토리 ( .) 아래 일반 파일 ( -type f)이고 f이름 ( -name '*f*')에 있는 모든 파일을 찾습니다 . 다음으로 sed파일 이름을 제거하고 디렉토리 이름 만 남겨 둡니다. 그런 다음 디렉토리 목록이 정렬 sort되고 ( uniq) 중복 항목이 제거됩니다 ( ).

sed명령은 단일 대체품으로 구성됩니다. 정규 표현식 /[^/]+$과 일치하는 항목을 찾고 일치하는 항목을 아무것도없는 것으로 바꿉니다. 달러 기호는 줄의 끝을 의미합니다. [^/]+'슬래시가 아닌 하나 이상의 문자를 의미합니다. 따라서 /[^/]+$마지막 슬래시에서 줄 끝까지의 모든 문자를 의미합니다. 즉, 전체 경로의 끝에있는 파일 이름과 일치합니다. 따라서 sed 명령은 파일 이름을 제거하고 파일이 있던 디렉토리의 이름은 변경하지 않습니다.

단순화

많은 현대 sort명령 -uuniq불필요한 플래그를 지원합니다 . GNU sed의 경우 :

find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort -u

그리고 MacOS sed의 경우 :

find . -type f -name '*f*' | sed -E 's|/[^/]+$||' |sort -u

또한 find명령이 지원하는 find경우 디렉토리 이름을 직접 인쇄 할 수 있습니다. 이렇게하면 다음이 필요하지 않습니다 sed.

find . -type f -name '*f*' -printf '%h\n' | sort -u

보다 강력한 버전 (GNU 도구 필요)

위의 버전은 줄 바꿈이 포함 된 파일 이름으로 혼동됩니다. 보다 강력한 솔루션은 NUL 종료 문자열을 정렬하는 것입니다.

find . -type f -name '*f*' -printf '%h\0' | sort -zu | sed -z 's/$/\n/'

파일을 너무 많이 정렬하는 파일이 많이 있습니다. uniq믹스에 던지면 이미 서로 인접한 반복되는 줄을 제거하여 많은 도움이됩니다. find . -type f -name '*f*' -printf '%h\0' | uniq -z | sort -zu | tr '\0' '\n'. 또는 도구가 약간 오래된 경우 uniq에 -z 옵션이 없을 수 있습니다. find . -type f -name '*f*' -printf '%h\n' | uniq | sort -u
jbo5112 2016 년

1
MacOS 사용자 : sed 플래그가 -r이 아닙니다. 어떤 이유로 그것의 -E
David

@David 매우 사실입니다. -EMacOS 용 으로 표시되도록 답변이 업데이트되었습니다 .
John1024

22

이것을 시도해보십시오.

find / -name '*f*' -printf "%h\n" | sort -u

가장 좋은 답변입니다. 위의 일부 답변과 달리 POSIX와 완전히 호환되며 또한 최단 파이프 라인 상을 수상합니다. :).
kkm

나는 이것이 가장 빠르다는 느낌을 받기 때문에 누군가가 위의 타이밍과 다른 타이밍을 보여주는 것을보고 싶습니다.
dlamblin

4
@kkm 이것이 최선의 해결책이지만 POSIX 사양find 은 실제로 매우 희박 합니다. -printf운영자가 지정 되지 않았습니다 . BSD에서는 작동하지 않습니다 find. 따라서 "완전히 POSIX 호환"이 아닙니다 . ( sort -u POSIX에 있습니다.)
와일드 카드

8

이를 위해 사용할 수있는 방법은 기본적으로 두 가지가 있습니다. 하나는 문자열을 구문 분석하고 다른 하나는 각 파일에서 작동합니다. 문자열을 파싱하는 것은 grep, 와 같은 도구를 사용 sed하거나 awk분명히 더 빠를 것입니다. 그러나 여기에는 두 가지 방법을 모두 "프로파일"하는 방법과 둘 다를 보여주는 예가 있습니다.

샘플 데이터

아래 예에서는 다음 데이터를 사용합니다.

$ touch dir{1..3}/dir{100..112}/file{1..5}
$ touch dir{1..3}/dir{100..112}/nile{1..5}
$ touch dir{1..3}/dir{100..112}/knife{1..5}

에서 일부 *f*파일을 삭제 하십시오 dir1/*.

$ rm dir1/dir10{0..2}/*f*

접근법 # 1-문자열을 통한 구문 분석

여기서는 다음과 같은 도구 findgrep, 및 을 사용합니다 sort.

$ find . -type f -name '*f*' | grep -o "\(.*\)/" | sort -u | head -5
./dir1/dir103/
./dir1/dir104/
./dir1/dir105/
./dir1/dir106/
./dir1/dir107/

접근법 # 2-파일을 사용한 구문 분석

이번에는 dirname대신에 사용할 도구를 제외하고 이전과 동일한 도구 체인 입니다 grep.

$ find . -type f -name '*f*' -exec dirname {} \; | sort -u | head -5
./dir1/dir103
./dir1/dir104
./dir1/dir105
./dir1/dir106
./dir1/dir107

참고 : 위의 예제는 head -5이러한 예제에서 처리하는 출력량을 제한하기 위해 사용 됩니다. 전체 목록을 얻으려면 일반적으로 삭제됩니다!

결과 비교

우리는 time두 가지 접근법을 살펴볼 수 있습니다 .

dirname

real        0m0.372s
user        0m0.028s
sys         0m0.106s

grep

real        0m0.012s
user        0m0.009s
sys         0m0.007s

따라서 가능한 경우 항상 문자열을 처리하는 것이 가장 좋습니다.

대체 문자열 파싱 방법

grep & PCRE

$ find . -type f -name '*f*' | grep  -oP '^.*(?=/)' | sort -u

sed

$ find . -type f -name '*f*' | sed 's#/[^/]*$##' | sort -u

어 wk

$ find . -type f -name '*f*' | awk -F'/[^/]*$' '{print $1}' | sort -u

그것은 작동하지만, 흥미롭게도이 여러 번 이상 John1024의 대답 @보다 오래 걸리는 일이기 때문에
Muhd

@Muhd-예 dirname 호출 속도가 느립니다. 대안을 찾고 있습니다.
slm

2

여기 내가 유용하다고 생각하는 것이 있습니다.

find . -type f -name "*somefile*" | xargs dirname | sort | uniq

1

이 답변은 부끄러운 답변을 기반으로합니다. 흥미로운 접근 방식이지만 파일 및 / 또는 디렉토리 이름에 특수 문자 (공백, 반열 ...)가있는 경우 제한이 있습니다. 좋은 습관은 사용하는 것 find /somewhere -print0 | xargs -0 someprogam입니다.

샘플 데이터

아래 예에서는 다음 데이터를 사용합니다.

mkdir -p dir{1..3}/dir\ {100..112}
touch dir{1..3}/dir\ {100..112}/nile{1..5}
touch dir{1..3}/dir\ {100..112}/file{1..5}
touch dir{1..3}/dir\ {100..112}/kni\ fe{1..5}

에서 일부 *f*파일을 삭제 하십시오 dir1/*/.

rm dir1/dir\ 10{0..2}/*f*

접근법 # 1-파일을 사용한 구문 분석

$ find -type f -name '*f*' -print0 | sed -e 's#/[^/]*\x00#\x00#g' | sort -zu | xargs -0 -n1 echo | head -n5
./dir1/dir 103
./dir1/dir 104
./dir1/dir 105
./dir1/dir 106
./dir1/dir 107

참고 : 위의 예제는 head -5이러한 예제에서 처리하는 출력량을 제한하기 위해 사용 됩니다. 전체 목록을 얻으려면 일반적으로 삭제됩니다! 또한 echo사용하려는 명령을 바꾸십시오 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.