리눅스 찾기-type d: ./dir1 없이 ./dir1/dir2와 같은 가장 깊은 디렉토리를 나열하는 방법은 무엇입니까?

리눅스 찾기-type d: ./dir1 없이 ./dir1/dir2와 같은 가장 깊은 디렉토리를 나열하는 방법은 무엇입니까?
find . -type d

일반적으로 표시됩니다

./dir1
./dir1/dir2
./dir3
./dir3/dir4
./dir3/dir4/dir5
...

나는 단지

./dir1/dir2
./dir3/dir4/dir5

, 상위 ./dir1 없음, ...

즉, 하위 디렉터리가 없는 디렉터리만 보고 싶습니다.

어떤 아이디어?

-links 2편집: 일반적인 Linux 환경에서 작동하는 것을 발견했습니다 . 예:

docker run -it --rm ubuntu:bionic find /etc -type d -links 2

완벽하게 작동합니다.

그러나 MacOS 또는 Windows의 디렉터리를 Docker 컨테이너에 마운트하면 상황이 변경되어 작동하지 않습니다. 다음을 시도해 볼 수 있습니다.

docker run -it --rm -v /etc:/etc_of_host ubuntu:bionic find /etc_of_host -type d -links 2

답변1

와 함께 zsh:

has_subdirs() () (( $# )) ${1-$REPLY}/*(ND/Y1)
print -rC1 -- **/*(ND/^+has_subdirs)

또는 중개 기능 없이 직접:

print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])

그것은:

  • fn() some-commandBourne-shell 및 대부분의 Bourne-like 쉘과 같은 몸체 fn로 함수를 정의합니다 .some-command
  • () { code } args위치 매개변수로 code실행 되는 익명 함수입니다 .args
  • (( $# ))여기서 해당 익명 함수의 본문은 다음을 해결하는 산술 표현식입니다.진실if $#(인수 개수)가 0이 아닙니다.
  • ${param-default}(Bourne 쉘에서) $param매개변수가 설정된 경우 또는 default그렇지 않은 경우로 확장됩니다. 여기서는 ${1-$REPLY}함수를 직접(으로) 호출 has_subdirs mydir하거나 아래와 같이 글로빙 한정자 함수로 호출할 수 있습니다.
  • $dir/*(ND/Y1)숨겨진 파일(otglob)을 포함하여 $dir( ) 에 있는 유형의 디렉토리 파일로 확장하고 , 일치하는 항목이 없어도( ullglob) 오류를 발생시키지 않습니다. 하지만 에서는 첫 번째 일치에서 멈춥니다. 따라서 디렉터리에 하위 디렉터리가 하나 이상 포함되어 있으면 익명 함수(및 )는 true를 반환합니다./DNY1has_subdirs
  • print -rC1olumn r에 인수 aw를 인쇄합니다.1 C
  • ^+has_subdirshas_subdirs함수가 true를 반환하지 않는( ) 파일로 제한됩니다 ^.

쉘을 사용해야 하는 경우 bash다음을 수행하십시오.

zsh << 'EOF'
  print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF

또는 결과를 bash 배열에 저장하려면(bash-4.4+ 필요):

readarray -td '' array < <(zsh << 'EOF'
  print -rNC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
)

(임의 경로를 저장할 수 있도록 NUL로 구분된 레코드 사용)

이 없지만 zsh이 있는 경우 perl다음을 수행할 수 있습니다.

find . -depth -type d -print0 |
  perl -l -0ne 'print if rindex $prev, "$_/", 0; $prev = $_'

또는 GNU가 있는 경우 awk:

find . -depth -type d -print0 |
  gawk -v 'RS=\0' 'index(prev, $0"/") != 1; {prev = $0}'

그 사람들은 find디렉토리를 인쇄 했습니다깊이 우선(그들이 있는 분기 이전에 나옴) 이전 레코드의 시작 부분에 뒤이어 발견되지 않은 레코드를 가져오거나 인쇄 perl합니다 .awk/

-l다시 말하지만, bash 4.4+ 배열에 파일을 저장하려면 after 또는 add -0in 을 이동하여 출력 시 NUL로 구분된 레코드로 전환하고 싶을 것입니다 .perl-v 'ORS=\0'gawk

readarray -td array < <(
  find . -depth -type d -print0 |
    perl -0lne 'print if rindex $prev, "$_/", 0; $prev = $_'
)
readarray -td array < <(
  find . -depth -type d -print0 |
    gawk -v 'RS=\0' -v 'ORS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
)

일부 시스템 및 파일 시스템(예: ext4Linux 기반 시스템의 파일 시스템)에서는 하위 디렉터리가 있는 디렉터리의 링크 수가 2보다 크다는 사실을 신뢰할 수 있습니다( dirdir/.각각에 대한 추가 링크 dir/subdir/..).

print -rC1 -- **/*(ND/l-3)

또는 find모든 쉘에서 사용:

find . -type d -links -3

btrfs예를 들어 디렉토리의 링크 수가 항상 1인 경우 (여러 Linux 배포판에서 기본 파일 시스템으로 대체됨 ) 에서는 작동하지 않으므로 ext4일반적인 솔루션으로 권장하지 않습니다.

overlayfs내가 찾은 곳 과 같이 귀하의 경우와 마찬가지로 통합 파일 시스템에도 동일합니다.병합된디렉토리에는 하위 디렉토리가 포함되어 있는지 여부에 관계없이 링크 수가 1입니다.

그러나 사용 가능한 모든 위치에서 디렉터리에 대한 읽기 액세스가 필요하지 않은 하위 디렉터리를 수동으로 계산하는 솔루션에 비해 이점이 있습니다(상위 디렉터리에 대한 검색 액세스만 가능).

답변2

당신이 찾고 있는 것은:

find . -type d -links 2

파일 시스템의 각 디렉토리에는 최소한 두 개의 하드 링크가 있습니다. 즉, 상위 디렉토리 자체와 '.' 기입. 하위 디렉토리의 각 '..' 항목은 디렉토리에 새로운 하드 링크를 추가합니다. 따라서 두 개의 하드 링크가 있는 디렉토리를 찾으면 됩니다.

다른 답변에서 제안된 명령

find . -type d -links -3

동일한 작업을 수행하지만 "3개 미만의 하드 링크가 있는 디렉토리"라는 설명이 있습니다.

답변3

가장 정렬된 것:

p="";(find . -type d;echo) | while read d; do [[ $p && $d != $p/* ]] && echo $p; p=$d; done

한 줄에

a="";(find . -type d;echo )|while read i; do if  [[ (! $i =~ $a) && ("$a" != "") ]]; then echo $a; fi; a=$i;done

op에서 언급했듯이 :

a="";(find . -type d;echo )|while read i; do [[ $i != $a/* && ! -z "$a" ]] && echo $a; a=$i;done

답변4

읽다 man find. 옵션 -mindepth은 당신이 원하는 것입니다.

관련 정보