위치, 폭이 먼저 모든 디렉토리를 재귀 적으로 나열하려면 어떻게해야합니까?

StackOverflow https://stackoverflow.com/questions/539583

  •  22-08-2019
  •  | 
  •  

문제

폭이 먼저 목록이 중요합니다. 또한 검색 된 깊이를 제한하는 것이 좋을 것입니다.

$ find . -type d
/foo
/foo/subfoo
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub
/bar
/bar/subbar

$ find . -type d -depth
/foo/subfoo/subsub/subsubsub
/foo/subfoo/subsub
/foo/subfoo
/foo
/bar/subbar
/bar

$ < what goes here? >
/foo
/bar
/foo/subfoo
/bar/subbar
/foo/subfoo/subsub
/foo/subfoo/subsub/subsubsub

가능하면 Bash One-Liner를 사용 하여이 작업을 수행하고 싶습니다. 자바 스크립트 쉘이 있다면

bash("find . -type d").sort( function (x) x.findall(/\//g).length; )
도움이 되었습니까?

해결책

그만큼 find 명령 지원 -printf 많은 자리 표시자를 인식하는 옵션.

그러한 자리 표시 자 중 하나입니다 %d 주어진 경로의 깊이를 어디에 상대적으로 렌더링하는 find 시작.

따라서 간단한 1 라이너를 사용할 수 있습니다.

find -type d -printf '%d\t%P\n' | sort -r -nk1 | cut -f2-

그것은 매우 간단하며 무거운 툴링에 의존하지 않습니다. perl.

작동 방식 :

  • 내부적으로 파일 목록을 생성하고 각각 2 장 라인으로 렌더링됩니다.
  • 첫 번째 필드에는 깊이가 포함되어 있으며 (역) 수치 정렬에 사용 된 다음 잘라냅니다.
  • 결과는 간단한 파일 목록, 최초의 최초의 순서로 한 줄 당 하나의 파일입니다.

다른 팁

표준 도구를 사용하여 수행하려면 다음 파이프 라인이 작동해야합니다.

find . -type d | perl -lne 'print tr:/::, " $_"' | sort -n | cut -d' ' -f2

그건,

  1. 여기에서 모든 디렉토리를 깊이있는 첫 번째 주문으로 찾아 인쇄하십시오.
  2. 각 디렉토리의 슬래시 수를 계산하고 경로로 전제하십시오.
  3. 깊이별로 정렬 (즉, 슬래시 수)
  4. 길을 추출하십시오.

발견 된 깊이를 제한하려면 -maxdepth 인수를 찾은 명령에 추가하십시오.

출력을 찾는 동일한 순서로 나열된 디렉토리를 원한다면 "Sort -n"대신 "Sort -n -s"를 사용하십시오. "-s"플래그는 정렬을 안정화시킵니다 (즉, 동일하게 비교하는 항목들 사이에 입력 순서가 보존됩니다).

디렉토리 계층을 통과 할 때 하향식 또는 상향식으로 깊이있는 첫 번째 검색을 원하기 때문에 내장 유틸리티를 사용하여 할 수 있다고 생각하지 않습니다. 다음은 폭이 큰 검색을 제공하는 파이썬 스크립트입니다.

import os, sys

rootdir = sys.argv[1]
queue = [rootdir]

while queue:
    file = queue.pop(0)
    print(file)
    if os.path.isdir(file):
        queue.extend(os.path.join(file,x) for x in os.listdir(file))

편집하다:

  1. 사용 os.path-대신 모듈 os.stat-기능 및 stat-기준 치수.
  2. 사용 list.pop 그리고 list.extend 대신에 del 그리고 += 운영자.

내 느낌은 이것이 이전에 언급 된 것보다 더 나은 솔루션이라는 것입니다. 여기에는 Grep과 그와 같은 루프가 포함되지만, 특히 완전한 찾기 버퍼가 아닌 라인 버퍼를 원하는 경우 특히 잘 작동합니다.

다음은 더 많은 리소스 집약적입니다.

  • 많은 포크
  • 많은 발견
  • 현재 깊이의 각 디렉토리는 파일 구조에 대한 전체 깊이가있는만큼 여러 번 찾기에 의해 타격을받습니다 (실제로 RAM의 양이 있으면 문제가되지 않아야합니다 ...)

이것은 다음과 같습니다.

  • Bash 및 기본 GNU 도구를 사용합니다
  • 원할 때마다 깨질 수 있습니다 (비행기를 찾는 것을 보는 것처럼)
  • 그것은 줄 당 작동하지 않고 찾을 때마다 작동하므로 후속 명령은 찾기와 종류를 기다릴 필요가 없습니다.
  • 실제 파일 시스템 분리를 기반으로 작동하므로 슬래시가있는 디렉토리가 있으면 더 깊이 나열되지 않습니다. 다른 경로 분리기가 구성된 경우에도 여전히 괜찮습니다.
#!/bin/bash 
depth=0

while find -mindepth $depth -maxdepth $depth | grep '.'
do
    depth=$((depth + 1))
done

당신은 또한 그것을 한 줄에 공정하게 (?) 쉽게 맞출 수 있습니다.

depth=0; while find -mindepth $depth -maxdepth $depth | grep --color=never '.'; do depth=$((depth + 1)); done

그러나 나는 타이핑보다 작은 스크립트를 선호합니다 ...

현재 디렉토리의 디렉토리 예 목록 아래에있는 find 명령, find/path/to/dir -type d를 사용할 수 있습니다.

find . -type d

나는 이것을 할 방법을 찾으려고 노력했다 find 그러나 그것은 a와 같은 것이없는 것 같습니다 -breadth 옵션. 패치를 쓰지 않아서 다음 쉘 주문을 시도하십시오 (배쉬 용) :

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
while test -n "$LIST"; do
    for F in $LIST; do
        echo $F;
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    LIST=$NLIST;
    NLIST="";
done

나는 우연히 이것을 우연히 발견했기 때문에 그것이 일반적으로 작동하는지 모르겠다 (나는 당신이 묻는 특정 디렉토리 구조에서만 테스트하고 있었다).

깊이를 제한하려면 외부 루프에 카운터 변수를 넣으십시오 (이에 주석도 추가).

# initialize the list of subdirectories being processed
LIST="$(find . -mindepth 1 -maxdepth 1 -type d)";
# initialize the depth counter to 0
let i=0;
# as long as there are more subdirectories to process and we haven't hit the max depth
while test "$i" -lt 2 -a -n "$LIST"; do
    # increment the depth counter
    let i++;
    # for each subdirectory in the current list
    for F in $LIST; do
        # print it
        echo $F;
        # double-check that it is indeed a directory, and if so
        # append its contents to the list for the next level
        test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)";
    done;
    # set the current list equal to the next level's list
    LIST=$NLIST;
    # clear the next level's list
    NLIST="";
done

(2 인치를 교체하십시오 -lt 2 깊이와 함께)

기본적으로 이것은 사용 사용 표준 폭이 먼저 검색 알고리즘을 구현합니다 $LIST 그리고 $NLIST 디렉토리 이름의 대기열로. 다음은 쉬운 카피 앤 페이스트를위한 1 라이너로서의 후자의 접근 방식입니다.

LIST="$(find . -mindepth 1 -maxdepth 1 -type d)"; let i=0; while test "$i" -lt 2 -a -n "$LIST"; do let i++; for F in $LIST; do echo $F; test -d "$F" && NLIST="$NLIST $(find $F -maxdepth 1 -mindepth 1 -type d)"; done; LIST=$NLIST; NLIST=""; done

자격이없는 순서없이 : -maxdepth -type d를 찾으십시오

자격이있는 주문을 얻으려면이 작은 쉘 스크립트와 함께 재귀를 직접 수행해야합니다.

#!/bin/bash
r () 
{
    let level=$3+1
    if [ $level -gt $4 ]; then return 0; fi
    cd "$1"
    for d in *; do
        if [ -d "$d" ]; then
            echo $2/$d
        fi;
    done
    for d in *; do
        if [ -d "$d" ]; then
            (r "$d" "$2/$d" $level $4)
        fi;
    done
}
r "$1" "$1" 0 "$2"

그런 다음 매개 변수 기준 디렉토리 및 깊이 로이 스크립트를 호출 할 수 있습니다.

다음은 찾기를 사용하여 가능한 방법입니다. 철저히 테스트하지 않았으므로 사용자는 조심해야합니다 ...

depth=0
output=$(find . -mindepth $depth -maxdepth $depth -type d | sort); 
until [[ ${#output} -eq 0 ]]; do 
  echo "$output"
  let depth=$depth+1
  output=$(find . -mindepth $depth -maxdepth $depth -type d | sort)
done

이 같은:

find . -type d | 
  perl -lne'push @_, $_;
    print join $/,
      sort { 
        length $a <=> length $b || 
          $a cmp $b 
        } @_ if eof'
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top