Linux에는 디렉토리 트리에서 브랜치의 끝(여기서는 나뭇잎이라고 부르겠습니다)인 디렉토리, 즉 하위 디렉토리가 없는 디렉토리만 찾는 방법이 있습니까? 내가 찾고 있어요이 문제하지만 한번도 제대로 된 답을 얻지 못했습니다.
그래서 디렉토리 트리가 있다면
root/
├── branch1
│ ├── branch11
│ │ └── branch111 *
│ └── branch12 *
└── branch2
├── branch21 *
└── branch22
└── branch221 *
분기 끝( 레이블이 붙은 디렉터리 *
)에서만 디렉터리를 찾을 수 있으므로 파일 수가 아닌 디렉터리 수만 볼 수 있습니까? 실제 사례에서는 파일이 포함된 파일을 찾고 있지만 해당 파일은 이 예에서 찾고자 하는 "나뭇잎"의 하위 집합입니다.
답변1
디렉터리가 아닌 파일이 포함된 리프 디렉터리만 찾으려면 인용된 질문에 대한 답변을 결합하면 됩니다.https://unix.stackexchange.com/a/203991/330217또는 비슷한 질문https://stackoverflow.com/a/4269862/10622916또는https://serverfault.com/a/530328find
와 함께! -empty
find rootdir -type d -links 2 ! -empty
하드 링크 확인은 -links 2
기존 UNIX 파일 시스템에서 작동합니다. 이 -empty
조건은 POSIX 표준의 일부는 아니지만 대부분의 Linux 시스템에서 사용할 수 있습니다.
KamilMaciorowski의 의견에 따르면 디렉토리의 전통적인 링크 수 의미는 Btrfs에 유효하지 않습니다. 이것은https://linux-btrfs.vger.kernel.narkive.com/oAoDX89D/btrfs-st-nlink-for-directoriesMac OS HFS+는 기존 동작에 대한 예외로도 언급됩니다. 이러한 파일 시스템의 경우 리프 디렉터리를 확인하려면 다른 방법이 필요합니다.
답변2
find
중첩을 사용 하고 하위 디렉터리 수를 계산할 수 있습니다 .
find . -type d \
\( -exec sh -c 'find "$1" -mindepth 1 -maxdepth 1 -type d -print0 | grep -cz "^" >/dev/null 2>&1' _ {} \; -o -print \)
답변3
그리고 zsh
:
leafdirs=( **/*(NDFl2) )
$leafdirs
일치하는 리프 디렉터리 목록으로 배열을 설정합니다.
다음을 사용하여 열에 aw를 print
나열 할 수 있습니다 .r
1
C
print -rC1 -- $leafdirs
또는 다음을 사용하여 반복합니다.
for dir ($leafdirs) something with $dir
이건 거의 번역이네@Bodo의 GNU find
답변, 이는 전통적인 Unix 계열 파일 시스템( ext4
이 구현과 같은) .
및 ..
실제 디렉토리 항목에서만 작동하는 것과 같습니다.
**/
: 모든 수준의 하위 디렉터리(NDFl2)
: 글로벌 예선N
:nullglob
이 glob을 활성화합니다. 일치하는 항목이 없어도 실패하지 않습니다. 대신 결과는 빈 목록입니다.D
: 이 glob 활성화dotglob
: 숨겨진 디렉터리를 보고 숨겨진 파일을 건너뛰지 않습니다.F
: 선택하다가득한디렉토리:.
및 이외의 항목이 하나 이상 포함된 디렉토리..
(GNUfind
와 유사-type d ! -empty
)l2
: 개수가 2개인 디렉터리만 연결합니다(예:-links 2
). 하나는 상위 디렉토리의 디렉토리 항목용이고 다른 하나는.
상위 디렉토리 내의 디렉토리 항목용입니다. 모든 하위 디렉토리에는 해당 항목 으로 인해..
링크 수에 하나가 추가됩니다 .
nlinks == 2가 불가능한 파일 시스템에서는 다음을 수행할 수 있습니다.
leafdirs=( **/*(NDF^e['()(($#)) $REPLY/*(ND/Y1)']) )
(이 코드에 저장된) 디렉터리에 하위 디렉터리가 있는지 확인하기 위해 e
한정자(negation 포함 )를 사용하여 코드를 실행합니다 . 여기서는 익명 함수를 사용하여 디렉터리 확장이 첫 번째 일치에서 중지되는지 확인합니다. 전달된 인수는 A입니다. 비어 있지 않은 목록(0이 아님).^
$REPLY
$REPLY/*(ND/Y1)
$REPLY
$#
답변4
파일 이름 와일드카드 패턴이 디렉터리 이름이 아닌 다른 이름으로 확장 되면 */
현재 디렉터리에 숨겨진 하위 디렉터리가 없는 것입니다.
그리고 find
:
find root -type d -exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; ! -empty -print
패턴이 심볼릭 링크를 통과하므로 리프 디렉터리에 있는 디렉터리에 대한 심볼릭 링크를 디렉터리로 처리합니다.
이 -empty
술어는 표준은 아니지만 자주 구현됩니다. 이것이 없으면 하위 디렉터리를 검색하는 것과 유사한 작업을 수행하게 됩니다.
find root -type d \
-exec sh -c 'set -- "$1"/*/; [ ! -d "$1" ]' sh {} \; \
-exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print
또는 더 효과적으로,
find root -type d -exec sh -c '
dir=$1
set -- "$dir"/*/
[ -d "$1" ] && exit 1
set -- "$dir"/*
[ -e "$1" ]' sh {} \; -print
아니면 -links
내가 잊어버린 술어를 선택하세요(고마워요 하카타):
find root -type d \
-links 2 \
-exec sh -c 'set -- "$1"/*; [ -e "$1" ]' sh {} \; -print